-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Connectors: Implement Odos connector (#158)
Co-authored-by: Facu Spagnuolo <facundo_spagnuolo@icloud.com>
- Loading branch information
1 parent
acc770e
commit 561915e
Showing
15 changed files
with
397 additions
and
14 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
packages/connectors/contracts/interfaces/odos/IOdosV2Connector.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
// 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 <http://www.gnu.org/licenses/>. | ||
|
||
pragma solidity >=0.8.0; | ||
|
||
/** | ||
* @title Odos V2 connector interface | ||
*/ | ||
interface IOdosV2Connector { | ||
/** | ||
* @dev The token in is the same as the token out | ||
*/ | ||
error OdosV2SwapSameToken(address token); | ||
|
||
/** | ||
* @dev The amount out is lower than the minimum amount out | ||
*/ | ||
error OdosV2BadAmountOut(uint256 amountOut, uint256 minAmountOut); | ||
|
||
/** | ||
* @dev The post token in balance is lower than the previous token in balance minus the amount in | ||
*/ | ||
error OdosV2BadPostTokenInBalance(uint256 postBalanceIn, uint256 preBalanceIn, uint256 amountIn); | ||
|
||
/** | ||
* @dev Tells the reference to Odos aggregation router v2 | ||
*/ | ||
function odosV2Router() external view returns (address); | ||
|
||
/** | ||
* @dev Executes a token swap in Odos V2 | ||
* @param tokenIn Token to be sent | ||
* @param tokenOut Token to be received | ||
* @param amountIn Amount of token in to be swapped | ||
* @param minAmountOut Minimum amount of token out willing to receive | ||
* @param data Calldata to be sent to the Odos aggregation router | ||
*/ | ||
function execute(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut, bytes memory data) | ||
external | ||
returns (uint256 amountOut); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
// 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 <http://www.gnu.org/licenses/>. | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; | ||
import '@openzeppelin/contracts/utils/Address.sol'; | ||
|
||
import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol'; | ||
|
||
import '../interfaces/odos/IOdosV2Connector.sol'; | ||
|
||
/** | ||
* @title OdosV2Connector | ||
* @dev Interfaces with Odos V2 to swap tokens | ||
*/ | ||
contract OdosV2Connector is IOdosV2Connector { | ||
// Reference to Odos aggregation router v2 | ||
address public immutable override odosV2Router; | ||
|
||
/** | ||
* @dev Creates a new OdosV2Connector contract | ||
* @param _odosV2Router Odos aggregation router v2 reference | ||
*/ | ||
constructor(address _odosV2Router) { | ||
odosV2Router = _odosV2Router; | ||
} | ||
|
||
/** | ||
* @dev Executes a token swap in Odos V2 | ||
* @param tokenIn Token to be sent | ||
* @param tokenOut Token to be received | ||
* @param amountIn Amount of token in to be swapped | ||
* @param minAmountOut Minimum amount of token out willing to receive | ||
* @param data Calldata to be sent to the Odos aggregation router | ||
*/ | ||
function execute(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut, bytes memory data) | ||
external | ||
override | ||
returns (uint256 amountOut) | ||
{ | ||
if (tokenIn == tokenOut) revert OdosV2SwapSameToken(tokenIn); | ||
|
||
uint256 preBalanceIn = IERC20(tokenIn).balanceOf(address(this)); | ||
uint256 preBalanceOut = IERC20(tokenOut).balanceOf(address(this)); | ||
|
||
ERC20Helpers.approve(tokenIn, odosV2Router, amountIn); | ||
Address.functionCall(odosV2Router, data, 'ODOS_V2_SWAP_FAILED'); | ||
|
||
uint256 postBalanceIn = IERC20(tokenIn).balanceOf(address(this)); | ||
bool isPostBalanceInUnexpected = postBalanceIn < preBalanceIn - amountIn; | ||
if (isPostBalanceInUnexpected) revert OdosV2BadPostTokenInBalance(postBalanceIn, preBalanceIn, amountIn); | ||
|
||
uint256 postBalanceOut = IERC20(tokenOut).balanceOf(address(this)); | ||
amountOut = postBalanceOut - preBalanceOut; | ||
if (amountOut < minAmountOut) revert OdosV2BadAmountOut(amountOut, minAmountOut); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import axios, { AxiosError } from 'axios' | ||
import { BigNumber, Contract } from 'ethers' | ||
|
||
const ODOS_URL = 'https://api.odos.xyz' | ||
export type SwapResponse = { data: { transaction: { data: string } } } | ||
|
||
export async function getOdosSwapData( | ||
chainId: number, | ||
sender: Contract, | ||
tokenIn: Contract, | ||
tokenOut: Contract, | ||
amountIn: BigNumber, | ||
slippage: number | ||
): Promise<string> { | ||
try { | ||
const response = await getSwap(chainId, sender, tokenIn, tokenOut, amountIn, slippage) | ||
return response.data.transaction.data | ||
} catch (error) { | ||
if (error instanceof AxiosError) throw Error(error.toString() + ' - ' + error.response?.data?.description) | ||
else throw error | ||
} | ||
} | ||
|
||
async function getSwap( | ||
chainId: number, | ||
sender: Contract, | ||
tokenIn: Contract, | ||
tokenOut: Contract, | ||
amountIn: BigNumber, | ||
slippage: number | ||
): Promise<SwapResponse> { | ||
const response = await axios.post( | ||
`${ODOS_URL}/sor/quote/v2`, | ||
{ | ||
chainId, | ||
inputTokens: [ | ||
{ | ||
tokenAddress: tokenIn.address, | ||
amount: amountIn.toString(), | ||
}, | ||
], | ||
outputTokens: [ | ||
{ | ||
tokenAddress: tokenOut.address, | ||
proportion: 1, | ||
}, | ||
], | ||
userAddr: sender.address, | ||
slippageLimitPercent: slippage < 1 ? slippage * 100 : slippage, // The value is 0.5 -> 0.5% | ||
}, | ||
{ | ||
headers: { | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json', | ||
}, | ||
} | ||
) | ||
const pathId = response.data.pathId | ||
return await axios.post( | ||
`${ODOS_URL}/sor/assemble`, | ||
{ | ||
userAddr: sender.address, | ||
pathId: pathId, | ||
}, | ||
{ | ||
headers: { | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json', | ||
}, | ||
} | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 0 additions & 7 deletions
7
packages/connectors/test/helpers/kyberswap/fixtures/8453/14845449/WETH-USDC.json
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.