diff --git a/contracts/zero-ex/CHANGELOG.json b/contracts/zero-ex/CHANGELOG.json index 9812e5b7d1..97bbaafc6b 100644 --- a/contracts/zero-ex/CHANGELOG.json +++ b/contracts/zero-ex/CHANGELOG.json @@ -10,6 +10,9 @@ }, { "note": "Add Base Mainnet and Goerli BridgeAdapters" + }, + { + "note": "Add Uniswap V3 support on Avalanche and BSC" } ] }, diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol b/contracts/zero-ex/contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol index f2ce9879c6..c8f836b565 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol @@ -28,6 +28,7 @@ import "./mixins/MixinNerve.sol"; import "./mixins/MixinPlatypus.sol"; import "./mixins/MixinTraderJoeV2.sol"; import "./mixins/MixinUniswapV2.sol"; +import "./mixins/MixinUniswapV3.sol"; import "./mixins/MixinWOOFi.sol"; import "./mixins/MixinZeroExBridge.sol"; @@ -44,6 +45,7 @@ contract AvalancheBridgeAdapter is MixinPlatypus, MixinTraderJoeV2, MixinUniswapV2, + MixinUniswapV3, MixinWOOFi, MixinZeroExBridge { @@ -72,6 +74,11 @@ contract AvalancheBridgeAdapter is return (0, true); } boughtAmount = _tradeUniswapV2(buyToken, sellAmount, order.bridgeData); + } else if (protocolId == BridgeProtocols.UNISWAPV3) { + if (dryRun) { + return (0, true); + } + boughtAmount = _tradeUniswapV3(sellToken, sellAmount, order.bridgeData); } else if (protocolId == BridgeProtocols.NERVE) { if (dryRun) { return (0, true); diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BSCBridgeAdapter.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BSCBridgeAdapter.sol index de7809a9a6..d98b16a946 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/BSCBridgeAdapter.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/BSCBridgeAdapter.sol @@ -25,6 +25,7 @@ import "./mixins/MixinKyberElastic.sol"; import "./mixins/MixinMooniswap.sol"; import "./mixins/MixinNerve.sol"; import "./mixins/MixinUniswapV2.sol"; +import "./mixins/MixinUniswapV3.sol"; import "./mixins/MixinWOOFi.sol"; import "./mixins/MixinZeroExBridge.sol"; @@ -38,6 +39,7 @@ contract BSCBridgeAdapter is MixinMooniswap, MixinNerve, MixinUniswapV2, + MixinUniswapV3, MixinWOOFi, MixinZeroExBridge { @@ -61,6 +63,11 @@ contract BSCBridgeAdapter is return (0, true); } boughtAmount = _tradeUniswapV2(buyToken, sellAmount, order.bridgeData); + } else if (protocolId == BridgeProtocols.UNISWAPV3) { + if (dryRun) { + return (0, true); + } + boughtAmount = _tradeUniswapV3(sellToken, sellAmount, order.bridgeData); } else if (protocolId == BridgeProtocols.MOONISWAP) { if (dryRun) { return (0, true); diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswapV3.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswapV3.sol index 1aedd28cc0..660938a8db 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswapV3.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswapV3.sol @@ -31,6 +31,18 @@ interface IUniswapV3Router { function exactInput(ExactInputParams memory params) external payable returns (uint256 amountOut); } +// https://github.com/Uniswap/swap-router-contracts/blob/main/contracts/interfaces/IV3SwapRouter.sol +interface IUniswapV3Router2 { + struct ExactInputParams { + bytes path; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; + } + + function exactInput(ExactInputParams memory params) external payable returns (uint256 amountOut); +} + contract MixinUniswapV3 { using LibERC20TokenV06 for IERC20Token; @@ -39,19 +51,30 @@ contract MixinUniswapV3 { uint256 sellAmount, bytes memory bridgeData ) internal returns (uint256 boughtAmount) { - (IUniswapV3Router router, bytes memory path) = abi.decode(bridgeData, (IUniswapV3Router, bytes)); + (address router, bytes memory path, uint256 routerVersion) = abi.decode(bridgeData, (address, bytes, uint256)); // Grant the Uniswap router an allowance to sell the sell token. - sellToken.approveIfBelow(address(router), sellAmount); + sellToken.approveIfBelow(router, sellAmount); - boughtAmount = router.exactInput( - IUniswapV3Router.ExactInputParams({ - path: path, - recipient: address(this), - deadline: block.timestamp, - amountIn: sellAmount, - amountOutMinimum: 1 - }) - ); + if (routerVersion != 2) { + boughtAmount = IUniswapV3Router(router).exactInput( + IUniswapV3Router.ExactInputParams({ + path: path, + recipient: address(this), + deadline: block.timestamp, + amountIn: sellAmount, + amountOutMinimum: 1 + }) + ); + } else { + boughtAmount = IUniswapV3Router2(router).exactInput( + IUniswapV3Router2.ExactInputParams({ + path: path, + recipient: address(this), + amountIn: sellAmount, + amountOutMinimum: 1 + }) + ); + } } } diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index 0727fb0311..9fda71f890 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -4,6 +4,9 @@ "changes": [ { "note": "Add Base mainnet addresses" + }, + { + "note": "Add UniswapV3 support in Avalanche and BSC FillQuoteTransformers" } ] }, diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index 82160a8cb6..d423c251b8 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -64,7 +64,7 @@ "wethTransformer": "0xac3d95668c092e895cd83a9cbafe9c7d9906471f", "payTakerTransformer": "0x7e788f3a3e39cdd1944ba111fafc5fb7e59b5e90", "affiliateFeeTransformer": "0x043300d113de0c64684ab89c56a45cd94c7ef54c", - "fillQuoteTransformer": "0x43d10801db01c28093265ef9b77d532e553fa578", + "fillQuoteTransformer": "0xa9c57c539690d4e1439411f648ead5b121b34a23", "positiveSlippageFeeTransformer": "0x6ff35e8cbaf56d8a8f6bf9963b902a4576243030" } }, @@ -156,7 +156,7 @@ "wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c", "payTakerTransformer": "0xb9a4c32547bc3cdc2ee2fb13cc1a0717dac9888f", "affiliateFeeTransformer": "0x105679f99d668001370b4621ad8648ac570c860f", - "fillQuoteTransformer": "0x886e4f97d7e06ab66dba574a7a861046dcf7ae4f", + "fillQuoteTransformer": "0x463fe1a80acb62ce1e4f0a4f7b83df674c2cce2c", "positiveSlippageFeeTransformer": "0xadbfdc58a24b6dbc16f21541800f43dd6e282250" } },