Skip to content

Commit

Permalink
Merge branch 'master' of github.com-facuspagnuolo:mimic-fi/v3-core in…
Browse files Browse the repository at this point in the history
…to connectors/implement_wormhole_bridge_connector
  • Loading branch information
facuspagnuolo committed Jun 26, 2023
2 parents 0d510d2 + 440c32c commit 81f3a28
Show file tree
Hide file tree
Showing 25 changed files with 637 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.5.0;

interface IUniswapV2Factory {
function getPair(address tokenA, address tokenB) external view returns (address);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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.6.2;

interface IUniswapV2Router02 {
function factory() external pure returns (address);

function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}
129 changes: 129 additions & 0 deletions packages/connectors/contracts/swap/uniswap-v2/UniswapV2Connector.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// 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 '@mimic-fi/v3-helpers/contracts/math/UncheckedMath.sol';
import '@mimic-fi/v3-helpers/contracts/utils/Arrays.sol';
import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol';

import './IUniswapV2Factory.sol';
import './IUniswapV2Router02.sol';

/**
* @title UniswapV2Connector
* @dev Interfaces with Uniswap V2 to swap tokens
*/
contract UniswapV2Connector {
using UncheckedMath for uint256;

// Reference to UniswapV2 router
IUniswapV2Router02 public immutable uniswapV2Router;

/**
* @dev Initializes the UniswapV2Connector contract
* @param _uniswapV2Router Uniswap V2 router reference
*/
constructor(address _uniswapV2Router) {
uniswapV2Router = IUniswapV2Router02(_uniswapV2Router);
}

/**
* @dev Executes a token swap in Uniswap V2
* @param tokenIn Token being sent
* @param tokenOut Token being received
* @param amountIn Amount of tokenIn being swapped
* @param minAmountOut Minimum amount of tokenOut willing to receive
* @param hopTokens Optional list of hop-tokens between tokenIn and tokenOut, only used for multi-hops
*/
function execute(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 minAmountOut,
address[] memory hopTokens
) external returns (uint256 amountOut) {
require(tokenIn != tokenOut, 'UNI_V2_SWAP_SAME_TOKEN');

uint256 preBalanceIn = IERC20(tokenIn).balanceOf(address(this));
uint256 preBalanceOut = IERC20(tokenOut).balanceOf(address(this));

ERC20Helpers.approve(tokenIn, address(uniswapV2Router), amountIn);
hopTokens.length == 0
? _singleSwap(tokenIn, tokenOut, amountIn, minAmountOut)
: _batchSwap(tokenIn, tokenOut, amountIn, minAmountOut, hopTokens);

uint256 postBalanceIn = IERC20(tokenIn).balanceOf(address(this));
require(postBalanceIn >= preBalanceIn - amountIn, 'UNI_V2_BAD_TOKEN_IN_BALANCE');

uint256 postBalanceOut = IERC20(tokenOut).balanceOf(address(this));
amountOut = postBalanceOut - preBalanceOut;
require(amountOut >= minAmountOut, 'UNI_V2_MIN_AMOUNT_OUT');
}

/**
* @dev Swap two tokens through UniswapV2 using a single hop
* @param tokenIn Token being sent
* @param tokenOut Token being received
* @param amountIn Amount of tokenIn being swapped
* @param minAmountOut Minimum amount of tokenOut willing to receive
*/
function _singleSwap(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut)
internal
returns (uint256[] memory)
{
address factory = uniswapV2Router.factory();
address[] memory tokens = Arrays.from(tokenIn, tokenOut);
_validatePool(factory, tokenIn, tokenOut);
return uniswapV2Router.swapExactTokensForTokens(amountIn, minAmountOut, tokens, address(this), block.timestamp);
}

/**
* @dev Swap two tokens through UniswapV2 using a multi hop
* @param tokenIn Token being sent
* @param tokenOut Token being received
* @param amountIn Amount of the first token in the path to be swapped
* @param minAmountOut Minimum amount of the last token in the path willing to receive
* @param hopTokens List of hop-tokens between tokenIn and tokenOut
*/
function _batchSwap(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 minAmountOut,
address[] memory hopTokens
) internal returns (uint256[] memory) {
address factory = uniswapV2Router.factory();
address[] memory tokens = Arrays.from(tokenIn, hopTokens, tokenOut);
// No need for checked math since we are using it to compute indexes manually, always within boundaries
for (uint256 i = 0; i < tokens.length.uncheckedSub(1); i = i.uncheckedAdd(1)) {
_validatePool(factory, tokens[i], tokens[i.uncheckedAdd(1)]);
}
return uniswapV2Router.swapExactTokensForTokens(amountIn, minAmountOut, tokens, address(this), block.timestamp);
}

/**
* @dev Validates that there is a pool created for tokenA and tokenB
* @param factory UniswapV2 factory to check against
* @param tokenA First token of the pair
* @param tokenB Second token of the pair
*/
function _validatePool(address factory, address tokenA, address tokenB) private view {
address pool = IUniswapV2Factory(factory).getPair(tokenA, tokenB);
require(pool != address(0), 'INVALID_UNISWAP_POOL');
}
}
47 changes: 47 additions & 0 deletions packages/connectors/src/1inch-v5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import axios, { AxiosError } from 'axios'
import { BigNumber, Contract } from 'ethers'

const ONE_INCH_URL = 'https://api.1inch.io/v5.0'

export type SwapResponse = { data: { tx: { data: string } } }

export async function get1inchSwapData(
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.tx.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> {
return axios.get(`${ONE_INCH_URL}/${chainId}/swap`, {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
params: {
disableEstimate: true,
fromAddress: sender.address,
fromTokenAddress: tokenIn.address,
toTokenAddress: tokenOut.address,
amount: amountIn.toString(),
slippage: slippage < 1 ? slippage * 100 : slippage,
},
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export function itBehavesLikeWormholeConnector(
context('when the recipient is not the zero address', async () => {
let amountIn: BigNumber
let minAmountOut: BigNumber

const relayerFee = bn(35000000)

beforeEach('set amount in and min amount out', async () => {
const decimals = await token.decimals()
amountIn = bn(300).mul(bn(10).pow(decimals))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"tokenOut": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"amountIn": "10000000000",
"slippage": 0.015,
"data": "0xe449022e00000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000020a42930000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f56408000000000000000000000004585fe77225b41b697c938b018e2ac67ac5a20c0cfee7c08"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"tokenOut": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"amountIn": "10000000000",
"slippage": 0.015,
"data": "0xe449022e00000000000000000000000000000000000000000000000000000002540be4000000000000000000000000000000000000000000000000004b88924a476a67cd0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640cfee7c08"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tokenIn": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"tokenOut": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"amountIn": "100000000",
"slippage": 0.015,
"data": "0xe449022e0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000695097f210000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000099ac8ca7087fa4a2a1fb6357269965a2014abc35cfee7c08"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tokenIn": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"tokenOut": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"amountIn": "1000000000000000000",
"slippage": 0.015,
"data": "0xe449022e0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006a1d73080000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000180000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640cfee7c08"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tokenIn": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"tokenOut": "0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6",
"amountIn": "10000000000",
"slippage": 0.01,
"data": "0x12aa3caf000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded10000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000001bfd67037b42cf73acf2047067bd4f2c47d9bfd6000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000502dcaf7b2a3ce981f1a6c86cc4634b16c7a836f00000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000020dd1670000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034900000000000000000000000000000000000000000000000000032b0002fd00a0c9e75c48000000000000000006040000000000000000000000000000000000000000000000000002cf00016200a007e5c0d200000000000000000000000000000000000000000000000000013e00004e4820cdc878c037625afe3a98e14fcc56e169f0b5b4112791bca1f2de4661ed88a30c99a7a9449aa84174dd93f59a000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded15120817eb46d60762442da3d931ff51a30334ca39b74c2132d05d31c914a87c6611c10748aeb04b58e8f00447dc20382000000000000000000000000c2132d05d31c914a87c6611c10748aeb04b58e8f0000000000000000000000001bfd67037b42cf73acf2047067bd4f2c47d9bfd600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000d2531e000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000910bf2d50fa5e014fd06666f456182d4ab7c8bd200a0c9e75c4800000000000000002e0400000000000000000000000000000000000000000000000000013f00004f02a00000000000000000000000000000000000000000000000000000000000193d96ee63c1e500eef1a9507b3d505f0062f2be9453981255b503c82791bca1f2de4661ed88a30c99a7a9449aa841745120817eb46d60762442da3d931ff51a30334ca39b742791bca1f2de4661ed88a30c99a7a9449aa8417400447dc203820000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000001bfd67037b42cf73acf2047067bd4f2c47d9bfd6000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000012240b2000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000910bf2d50fa5e014fd06666f456182d4ab7c8bd280a06c4eca271bfd67037b42cf73acf2047067bd4f2c47d9bfd61111111254eeb25477b68fb85ed929f73a9605820000000000000000000000000000000000000000000000cfee7c08"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tokenIn": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"tokenOut": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
"amountIn": "10000000000",
"slippage": 0.01,
"data": "0x12aa3caf000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded10000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f619000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000502dcaf7b2a3ce981f1a6c86cc4634b16c7a836f00000000000000000000000000000000000000000000000000000002540be4000000000000000000000000000000000000000000000000004be68b4294b17097000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000019b00016d00a0c9e75c4800000000000000001d1500000000000000000000000000000000000000000000000000013f00004f02a00000000000000000000000000000000000000000000000001fe1020a515147a5ee63c1e50145dda9cb7c25131df268515131f647d726f506082791bca1f2de4661ed88a30c99a7a9449aa841745120817eb46d60762442da3d931ff51a30334ca39b742791bca1f2de4661ed88a30c99a7a9449aa8417400447dc203820000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000002c058938436028f1000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000910bf2d50fa5e014fd06666f456182d4ab7c8bd280a06c4eca277ceb23fd6bc0add59e62ac25578270cff1b9f6191111111254eeb25477b68fb85ed929f73a96058200000000000000cfee7c08"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tokenIn": "0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6",
"tokenOut": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"amountIn": "100000000",
"slippage": 0.01,
"data": "0x12aa3caf000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded10000000000000000000000001bfd67037b42cf73acf2047067bd4f2c47d9bfd60000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000502dcaf7b2a3ce981f1a6c86cc4634b16c7a836f0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000069c865a6a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004b600000000000000000000000000000000000000000000000000049800046a00a0c9e75c480000000000000005030200000000000000000000000000000000000000000000043c0002800000c200a007e5c0d200000000000000000000000000000000000000000000000000009e00004f02a00000000000000000000000000000000000000000000000002b989e7177123e55ee63c1e501ac4494e30a85369e332bdb5230d6d694d4259dbc1bfd67037b42cf73acf2047067bd4f2c47d9bfd602a000000000000000000000000000000000000000000000000000000001528b4d1aee63c1e50045dda9cb7c25131df268515131f647d726f506087ceb23fd6bc0add59e62ac25578270cff1b9f61900a007e5c0d200000000000000000000000000000000000000000000000000019a0000f05120817eb46d60762442da3d931ff51a30334ca39b741bfd67037b42cf73acf2047067bd4f2c47d9bfd600447dc203820000000000000000000000001bfd67037b42cf73acf2047067bd4f2c47d9bfd6000000000000000000000000c2132d05d31c914a87c6611c10748aeb04b58e8f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001fbc68e67000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000910bf2d50fa5e014fd06666f456182d4ab7c8bd200a0c9e75c480000000000000000250d00000000000000000000000000000000000000000000000000007c00002e00a0a87a1ae8813fddeccd0401c4fa73b092b074802440544e52c2132d05d31c914a87c6611c10748aeb04b58e8f4820cdc878c037625afe3a98e14fcc56e169f0b5b411c2132d05d31c914a87c6611c10748aeb04b58e8fbd6015b4000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded100a0c9e75c48000000000000002a040400000000000000000000000000000000000000000000018e00009e00004f02a00000000000000000000000000000000000000000000000000000000043b5da82ee63c1e501a5cd8351cbf30b531c7b11b0d9d3ff38ea2e280f1bfd67037b42cf73acf2047067bd4f2c47d9bfd602a00000000000000000000000000000000000000000000000000000000043b64c29ee63c1e501eef1a9507b3d505f0062f2be9453981255b503c81bfd67037b42cf73acf2047067bd4f2c47d9bfd65120817eb46d60762442da3d931ff51a30334ca39b741bfd67037b42cf73acf2047067bd4f2c47d9bfd600447dc203820000000000000000000000001bfd67037b42cf73acf2047067bd4f2c47d9bfd60000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000002c6d88379000000000000000000000000cfd674f8731e801a4a15c1ae31770960e1afded1000000000000000000000000910bf2d50fa5e014fd06666f456182d4ab7c8bd280a06c4eca272791bca1f2de4661ed88a30c99a7a9449aa841741111111254eeb25477b68fb85ed929f73a96058200000000000000000000cfee7c08"
}
Loading

0 comments on commit 81f3a28

Please sign in to comment.