Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Emiswap adapters #162

Open
wants to merge 1 commit into
base: interactive-updates
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions contracts/adapters/emiswap/EmiswapExchangeAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (C) 2020 Zerion Inc. <https://zerion.io>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: LGPL-3.0-only

pragma solidity >=0.7.6;
pragma experimental ABIEncoderV2;

import { ERC20 } from "../../interfaces/ERC20.sol";
import { ProtocolAdapter } from "../ProtocolAdapter.sol";

/**
* @title Adapter for Emiswap protocol (exchange).
* @dev Implementation of ProtocolAdapter abstract contract.
* Base contract for Emiswap exchange adapter.
* @author Eugene Rupakov <[email protected]>
*/
contract EmiswapExchangeAdapter is ProtocolAdapter {
/**
* @notice This function is unavailable for exchange adapter.
* @dev Implementation of ProtocolAdapter abstract contract function.
*/
function getBalance(address, address) public override returns (int256) {
revert("EEA: no balance");
}
}
83 changes: 83 additions & 0 deletions contracts/adapters/emiswap/EmiswapTokenAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (C) 2020 Zerion Inc. <https://zerion.io>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: LGPL-3.0-only

pragma solidity >=0.7.6;
pragma experimental ABIEncoderV2;

import { ERC20 } from "../../interfaces/ERC20.sol";
import { Component } from "../../shared/Structs.sol";
import { TokenAdapter } from "../TokenAdapter.sol";
import { Helpers } from "../../shared/Helpers.sol";
import { IEmiswap } from "../../interfaces/IEmiswap.sol";

/**
* @title Token adapter for Emiswap Pool Tokens.
* @dev Implementation of TokenAdapter abstract contract.
* @author Eugene Rupakov <[email protected]>
*/
contract EmiswapTokenAdapter is TokenAdapter {
using Helpers for bytes32;

/**
* @return Array of Component structs with underlying tokens rates for the given token.
* @dev Implementation of TokenAdapter abstract contract function.
*/
function getComponents(address token) external override returns (Component[] memory) {
address[] memory tokens = new address[](2);
tokens[0] = address(IEmiswap(token).tokens(0));
tokens[1] = address(IEmiswap(token).tokens(1));
uint256 totalSupply = ERC20(token).totalSupply();

Component[] memory components = new Component[](2);

for (uint256 i = 0; i < 2; i++) {
components[i] = Component({
token: tokens[i],
rate: int256((ERC20(tokens[i]).balanceOf(token) * 1e18) / totalSupply)
});
}

return components;
}

/**
* @return Pool name.
*/
function getName(address token) internal view override returns (string memory) {
return
string(
abi.encodePacked(
getUnderlyingSymbol(address(IEmiswap(token).tokens(0))),
"/",
getUnderlyingSymbol(address(IEmiswap(token).tokens(1))),
" Pool"
)
);
}

function getUnderlyingSymbol(address token) internal view returns (string memory) {
(, bytes memory returnData) = token.staticcall(
abi.encodeWithSelector(ERC20(token).symbol.selector)
);

if (returnData.length == 32) {
return abi.decode(returnData, (bytes32)).toString();
} else {
return abi.decode(returnData, (string));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (C) 2020 Zerion Inc. <https://zerion.io>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: LGPL-3.0-only

pragma solidity >=0.7.6;
pragma experimental ABIEncoderV2;

import { ERC20 } from "../../interfaces/ERC20.sol";
import { SafeERC20 } from "../../shared/SafeERC20.sol";
import { TokenAmount } from "../../shared/Structs.sol";
import { ERC20ProtocolAdapter } from "../../adapters/ERC20ProtocolAdapter.sol";
import { InteractiveAdapter } from "../InteractiveAdapter.sol";
import "../../interfaces/IEmiswap.sol";

/**
* @title Interactive adapter for Emiswap protocol (liquidity).
* @dev Implementation of InteractiveAdapter abstract contract.
* @author Igor Sobolev <[email protected]>
*/
contract EmiswapV2AssetInteractiveAdapter is InteractiveAdapter, ERC20ProtocolAdapter {
using SafeERC20 for ERC20;

address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

/**
* @notice Deposits tokens to the Uniswap pool (pair).
* @param tokenAmounts Array with one element - TokenAmount struct with
* underlying tokens addresses, underlying tokens amounts to be deposited, and amount types.
* @param data ABI-encoded additional parameters:
* - pair - pair address.
* @return tokensToBeWithdrawn Array with one element - UNI-token (pair) address.
* @dev Implementation of InteractiveAdapter function.
*/
function deposit(TokenAmount[] calldata tokenAmounts, bytes calldata data)
external
payable
override
returns (address[] memory tokensToBeWithdrawn)
{
require(tokenAmounts.length == 2, "ELIA: should be 2 tokenAmounts");

address pair = abi.decode(data, (address));

uint256 [] memory a = new uint256[](2);
uint256 [] memory minA = new uint256[](2);

a[0] = getAbsoluteAmountDeposit(tokenAmounts[0]);
a[1] = getAbsoluteAmountDeposit(tokenAmounts[1]);

tokensToBeWithdrawn = new address[](2);
tokensToBeWithdrawn[0] = tokenAmounts[0].token;
tokensToBeWithdrawn[1] = tokenAmounts[1].token;

// solhint-disable-next-line no-empty-blocks

try IEmiswap(pair).deposit(a, minA, address(0)) returns (uint256) {} catch Error(
string memory reason
) {
revert(reason);
} catch {
revert("ELIA: deposit fail");
}
}

/**
* @notice Withdraws tokens from the Uniswap pool.
* @param tokenAmounts Array with one element - TokenAmount struct with
* UNI token address, UNI token amount to be redeemed, and amount type.
* @return tokensToBeWithdrawn Array with two elements - underlying tokens.
* @dev Implementation of InteractiveAdapter function.
*/
function withdraw(TokenAmount[] calldata tokenAmounts, bytes calldata)
external
payable
override
returns (address[] memory tokensToBeWithdrawn)
{
require(tokenAmounts.length == 1, "ELIA: should be 1 tokenAmount");

address token = tokenAmounts[0].token;
uint256 amount = getAbsoluteAmountWithdraw(tokenAmounts[0]);

tokensToBeWithdrawn = new address[](2);
tokensToBeWithdrawn[0] = address(IEmiswap(token).tokens(0));
tokensToBeWithdrawn[1] = address(IEmiswap(token).tokens(1));

// solhint-disable-next-line no-empty-blocks
uint256 [] memory minReturns = new uint256[](2);

try IEmiswap(token).withdraw(amount, minReturns) {} catch Error(
string memory reason
) {
revert(reason);
} catch {
revert("ELIA: withdraw fail");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright (C) 2020 Zerion Inc. <https://zerion.io>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: LGPL-3.0-only

pragma solidity >=0.7.6;
pragma experimental ABIEncoderV2;

import { ERC20 } from "../../interfaces/ERC20.sol";
import { SafeERC20 } from "../../shared/SafeERC20.sol";
import { TokenAmount, AmountType } from "../../shared/Structs.sol";
import { EmiswapExchangeAdapter } from "../../adapters/emiswap/EmiswapExchangeAdapter.sol";
import { InteractiveAdapter } from "../InteractiveAdapter.sol";
import "../../interfaces/IEmiRouter.sol";

/**
* @title Interactive adapter for Emiswap protocol (exchange).
* @dev Implementation of InteractiveAdapter abstract contract.
* @author Eugene Rupakov <[email protected]>
*/
contract EmiswapExchangeInteractiveAdapter is InteractiveAdapter, EmiswapExchangeAdapter {
using SafeERC20 for ERC20;

address internal constant ROUTER = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;

/**
* @notice Exchange tokens using Uniswap pool.
* @param tokenAmounts Array with one element - TokenAmount struct with
* "from" token address, "from" token amount, and amount type.
* @param data Uniswap exchange path starting from tokens[0] (ABI-encoded).
* @return tokensToBeWithdrawn Array with one element - token address to be exchanged to.
* @dev Implementation of InteractiveAdapter function.
*/
function deposit(TokenAmount[] calldata tokenAmounts, bytes calldata data)
external
payable
override
returns (address[] memory tokensToBeWithdrawn)
{
require(tokenAmounts.length == 1, "EEIA: should be 1 tokenAmount");

address[] memory path = abi.decode(data, (address[]));
address token = tokenAmounts[0].token;
require(token == path[0], "EEIA: bad path[0]");
uint256 amount = getAbsoluteAmountDeposit(tokenAmounts[0]);

tokensToBeWithdrawn = new address[](1);
tokensToBeWithdrawn[0] = path[path.length - 1];

ERC20(token).safeApprove(ROUTER, amount, "EEIA[1]");

try
IEmiRouter(ROUTER).swapExactTokensForTokens(
amount,
0,
path,
address(this),
// solhint-disable-next-line not-rely-on-time
address(0)
)
returns (uint256[] memory) {} catch Error(string memory reason) {
//solhint-disable-previous-line no-empty-blocks
revert(reason);
} catch {
revert("EEIA: deposit fail");
}
}

/**
* @notice Exchange tokens using Uniswap pool.
* @param tokenAmounts Array with one element - TokenAmount struct with
* "to" token address, "to" token amount, and amount type (must be absolute).
* @param data Uniswap exchange path ending with tokens[0] (ABI-encoded).
* @return tokensToBeWithdrawn Array with one element - token address to be changed to.
* @dev Implementation of InteractiveAdapter function.
*/
function withdraw(TokenAmount[] calldata tokenAmounts, bytes calldata data)
external
payable
override
returns (address[] memory tokensToBeWithdrawn)
{
require(tokenAmounts.length == 1, "EEIA: should be 1 tokenAmount");
require(tokenAmounts[0].amountType == AmountType.Absolute, "EEIA: bad type");

address[] memory path = abi.decode(data, (address[]));
address token = tokenAmounts[0].token;
require(token == path[path.length - 1], "EEIA: bad path[path.length - 1]");
uint256 amount = tokenAmounts[0].amount;

tokensToBeWithdrawn = new address[](1);
tokensToBeWithdrawn[0] = token;

ERC20(path[0]).safeApprove(ROUTER, ERC20(path[0]).balanceOf(address(this)), "EEIA[2]");

try
IEmiRouter(ROUTER).swapTokensForExactTokens(
amount,
type(uint256).max,
path,
address(this),
// solhint-disable-next-line not-rely-on-time
address(0)
)
returns (uint256[] memory) {} catch Error(string memory reason) {
//solhint-disable-previous-line no-empty-blocks
revert(reason);
} catch {
revert("EEIA: withdraw fail");
}

ERC20(path[0]).safeApprove(ROUTER, 0, "EEIA[3]");
}
}
Loading