From f5c486050b91d61a60fa42f449561a4ef79e65b7 Mon Sep 17 00:00:00 2001 From: Noah Khamliche Date: Thu, 2 Jun 2022 12:02:41 -0400 Subject: [PATCH] added bancor mixin/sampler and started linking up with asset-swapper --- .../transformers/bridges/BridgeProtocols.sol | 1 + .../bridges/EthereumBridgeAdapter.sol | 11 ++- .../bridges/mixins/MixinBancorV3.sol | 94 ++++++++++++++++++ contracts/zero-ex/package.json | 2 +- contracts/zero-ex/test/artifacts.ts | 2 + contracts/zero-ex/test/wrappers.ts | 1 + contracts/zero-ex/tsconfig.json | 1 + .../contracts/src/BancorV3Sampler.sol | 98 +++++++++++++++++++ .../contracts/src/ERC20BridgeSampler.sol | 2 + .../contracts/src/interfaces/IBancorV3.sol | 43 ++++++++ packages/asset-swapper/package.json | 2 +- .../utils/market_operation_utils/constants.ts | 17 ++++ .../utils/market_operation_utils/orders.ts | 6 +- .../sampler_operations.ts | 46 +++++++++ .../src/utils/market_operation_utils/types.ts | 6 ++ packages/asset-swapper/test/artifacts.ts | 4 + packages/asset-swapper/test/wrappers.ts | 2 + packages/asset-swapper/tsconfig.json | 2 + .../protocol-utils/src/transformer_utils.ts | 1 + 19 files changed, 337 insertions(+), 4 deletions(-) create mode 100644 contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinBancorV3.sol create mode 100644 packages/asset-swapper/contracts/src/BancorV3Sampler.sol create mode 100644 packages/asset-swapper/contracts/src/interfaces/IBancorV3.sol diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol index d7ff6914bd..ffffd9dc58 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol @@ -55,4 +55,5 @@ library BridgeProtocols { uint128 internal constant BALANCERV2BATCH = 25; uint128 internal constant GMX = 26; uint128 internal constant PLATYPUS = 27; + uint128 internal constant BANCORV3 = 28; } diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/EthereumBridgeAdapter.sol b/contracts/zero-ex/contracts/src/transformers/bridges/EthereumBridgeAdapter.sol index 3a0efc30a8..132cba58dc 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/EthereumBridgeAdapter.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/EthereumBridgeAdapter.sol @@ -27,6 +27,7 @@ import "./mixins/MixinBalancer.sol"; import "./mixins/MixinBalancerV2.sol"; import "./mixins/MixinBalancerV2Batch.sol"; import "./mixins/MixinBancor.sol"; +import "./mixins/MixinBancorV3.sol"; import "./mixins/MixinCompound.sol"; import "./mixins/MixinCurve.sol"; import "./mixins/MixinCurveV2.sol"; @@ -52,6 +53,7 @@ contract EthereumBridgeAdapter is MixinBalancerV2, MixinBalancerV2Batch, MixinBancor, + MixinBancorV3, MixinCompound, MixinCurve, MixinCurveV2, @@ -250,8 +252,15 @@ contract EthereumBridgeAdapter is sellAmount, order.bridgeData ); + } else if (protocolId == BridgeProtocols.BANCORV3) { + if (dryRun) { return (0, true); } + boughtAmount = _tradeBancorV3( + buyToken, + sellAmount, + order.bridgeData + ); } else if (protocolId == BridgeProtocols.UNKNOWN) { - if (dryRun) { return (0, true); } + if (dryRun) { return (0, true); } boughtAmount = _tradeZeroExBridge( sellToken, buyToken, diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinBancorV3.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinBancorV3.sol new file mode 100644 index 0000000000..74c9487f5e --- /dev/null +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinBancorV3.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: Apache-2.0 + +/* + + Copyright 2020 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.6.5; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; +import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; + +/* + BancorV3 +*/ +interface IBancorV3 { + /** + * @dev performs a trade by providing the source amount and returns the target amount and the associated fee + * + * requirements: + * + * - the caller must be the network contract + */ + function tradeBySourceAmount( + address sourceToken, + address targetToken, + uint256 sourceAmount, + uint256 minReturnAmount, + uint256 deadline, + address beneficiary + ) external returns (uint256 amount); +} + +contract MixinBancorV3 { + + using LibERC20TokenV06 for IERC20TokenV06; + + function _tradeBancorV3( + IERC20TokenV06 buyToken, + uint256 sellAmount, + bytes memory bridgeData + ) + public + returns (uint256 amountOut) + + { + IBancorV3 router; + IERC20TokenV06[] memory path; + address[] memory _path; + { + (router, _path) = abi.decode(bridgeData, (IBancorV3, address[])); + // To get around `abi.decode()` not supporting interface array types. + assembly { path := _path } + } + + require(path.length >= 2, "MixinBancorV3/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); + require( + path[path.length - 1] == buyToken, + "MixinBancorV3/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN" + ); + // Grant the BancorV3 router an allowance to sell the first token. + path[0].approveIfBelow(address(router), sellAmount); + + + uint256 amountOut = router.tradeBySourceAmount( + _path[0], + _path[1], + // Sell all tokens we hold. + sellAmount, + // Minimum buy amount. + 1, + //deadline + block.timestamp + 1, + // address of the mixin + address(this) + ); + + return amountOut; + } +} \ No newline at end of file diff --git a/contracts/zero-ex/package.json b/contracts/zero-ex/package.json index 787b47e4d5..84eaeeb9bb 100644 --- a/contracts/zero-ex/package.json +++ b/contracts/zero-ex/package.json @@ -43,7 +43,7 @@ "config": { "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature,AvalancheBridgeAdapter,BSCBridgeAdapter,CeloBridgeAdapter,EthereumBridgeAdapter,FantomBridgeAdapter,OptimismBridgeAdapter,PolygonBridgeAdapter", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(AbstractBridgeAdapter|AffiliateFeeTransformer|AvalancheBridgeAdapter|BSCBridgeAdapter|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeProtocols|CeloBridgeAdapter|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|EthereumBridgeAdapter|FantomBridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBalancerV2Batch|MixinBancor|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinPlatypus|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OptimismBridgeAdapter|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PolygonBridgeAdapter|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json" + "abis": "./test/generated-artifacts/@(AbstractBridgeAdapter|AffiliateFeeTransformer|AvalancheBridgeAdapter|BSCBridgeAdapter|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeProtocols|CeloBridgeAdapter|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|EthereumBridgeAdapter|FantomBridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBalancerV2Batch|MixinBancor|MixinBancorV3|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinPlatypus|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OptimismBridgeAdapter|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PolygonBridgeAdapter|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json" }, "repository": { "type": "git", diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts index c3ef2bcde7..a3f712a28b 100644 --- a/contracts/zero-ex/test/artifacts.ts +++ b/contracts/zero-ex/test/artifacts.ts @@ -108,6 +108,7 @@ import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json'; import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json'; import * as MixinBalancerV2Batch from '../test/generated-artifacts/MixinBalancerV2Batch.json'; import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json'; +import * as MixinBancorV3 from '../test/generated-artifacts/MixinBancorV3.json'; import * as MixinCompound from '../test/generated-artifacts/MixinCompound.json'; import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json'; import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json'; @@ -329,6 +330,7 @@ export const artifacts = { MixinBalancerV2: MixinBalancerV2 as ContractArtifact, MixinBalancerV2Batch: MixinBalancerV2Batch as ContractArtifact, MixinBancor: MixinBancor as ContractArtifact, + MixinBancorV3: MixinBancorV3 as ContractArtifact, MixinCompound: MixinCompound as ContractArtifact, MixinCryptoCom: MixinCryptoCom as ContractArtifact, MixinCurve: MixinCurve as ContractArtifact, diff --git a/contracts/zero-ex/test/wrappers.ts b/contracts/zero-ex/test/wrappers.ts index db70cfdead..86eaca1826 100644 --- a/contracts/zero-ex/test/wrappers.ts +++ b/contracts/zero-ex/test/wrappers.ts @@ -106,6 +106,7 @@ export * from '../test/generated-wrappers/mixin_balancer'; export * from '../test/generated-wrappers/mixin_balancer_v2'; export * from '../test/generated-wrappers/mixin_balancer_v2_batch'; export * from '../test/generated-wrappers/mixin_bancor'; +export * from '../test/generated-wrappers/mixin_bancor_v3'; export * from '../test/generated-wrappers/mixin_compound'; export * from '../test/generated-wrappers/mixin_crypto_com'; export * from '../test/generated-wrappers/mixin_curve'; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json index efcb47a611..36c1624418 100644 --- a/contracts/zero-ex/tsconfig.json +++ b/contracts/zero-ex/tsconfig.json @@ -145,6 +145,7 @@ "test/generated-artifacts/MixinBalancerV2.json", "test/generated-artifacts/MixinBalancerV2Batch.json", "test/generated-artifacts/MixinBancor.json", + "test/generated-artifacts/MixinBancorV3.json", "test/generated-artifacts/MixinCompound.json", "test/generated-artifacts/MixinCryptoCom.json", "test/generated-artifacts/MixinCurve.json", diff --git a/packages/asset-swapper/contracts/src/BancorV3Sampler.sol b/packages/asset-swapper/contracts/src/BancorV3Sampler.sol new file mode 100644 index 0000000000..b9a81150c2 --- /dev/null +++ b/packages/asset-swapper/contracts/src/BancorV3Sampler.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + + Copyright 2022 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.6; +pragma experimental ABIEncoderV2; + +import "./interfaces/IBancorV3.sol"; + + +contract BancorV3Sampler +{ + /// @dev Gas limit for BancorV3 calls. + uint256 constant private BancorV3_CALL_GAS = 150e3; // 150k + + /// @dev Sample sell quotes from BancorV3. + /// @param router Router to look up tokens and amounts + /// @param path Token route. Should be takerToken -> makerToken + /// @param takerTokenAmounts Taker token sell amount for each sample. + /// @return makerTokenAmounts Maker amounts bought at each taker token + /// amount. + function sampleSellsFromBancorV3( + address router, + address[] memory path, + uint256[] memory takerTokenAmounts + ) + public + view + returns (uint256[] memory makerTokenAmounts) + { + uint256 numSamples = takerTokenAmounts.length; + makerTokenAmounts = new uint256[](numSamples); + for (uint256 i = 0; i < numSamples; i++) { + try + IBancorV3(router).tradeOutputBySourceAmount(path[0], path[1], takerTokenAmounts[i]) + returns (uint256 amount) + { + makerTokenAmounts[i] = amount; + // Break early if there are 0 amounts + if (makerTokenAmounts[i] == 0) { + break; + } + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + break; + } + } + } + + /// @dev Sample buy quotes from BancorV3. + /// @param router Router to look up tokens and amounts + /// @param path Token route. Should be takerToken -> makerToken. + /// @param makerTokenAmounts Maker token buy amount for each sample. + /// @return takerTokenAmounts Taker amounts sold at each maker token + /// amount. + function sampleBuysFromBancorV3( + address router, + address[] memory path, + uint256[] memory makerTokenAmounts + ) + public + view + returns (uint256[] memory takerTokenAmounts) + { + uint256 numSamples = makerTokenAmounts.length; + takerTokenAmounts = new uint256[](numSamples); + for (uint256 i = 0; i < numSamples; i++) { + try + IBancorV3(router).tradeInputByTargetAmount(path[0], path[1], makerTokenAmounts[i]) + returns (uint256 amount) + { + takerTokenAmounts[i] = amount; + // Break early if there are 0 amounts + if (takerTokenAmounts[i] == 0) { + break; + } + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + break; + } + } + } +} \ No newline at end of file diff --git a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol index 6c7304d305..3747a0ad88 100644 --- a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol +++ b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol @@ -24,6 +24,7 @@ import "./BalancerSampler.sol"; import "./BalancerV2Sampler.sol"; import "./BalancerV2BatchSampler.sol"; import "./BancorSampler.sol"; +import "./BancorV3Sampler.sol"; import "./CompoundSampler.sol"; import "./CurveSampler.sol"; import "./DODOSampler.sol"; @@ -51,6 +52,7 @@ contract ERC20BridgeSampler is BalancerV2Sampler, BalancerV2BatchSampler, BancorSampler, + BancorV3Sampler, CompoundSampler, CurveSampler, DODOSampler, diff --git a/packages/asset-swapper/contracts/src/interfaces/IBancorV3.sol b/packages/asset-swapper/contracts/src/interfaces/IBancorV3.sol new file mode 100644 index 0000000000..0b5bed9f8f --- /dev/null +++ b/packages/asset-swapper/contracts/src/interfaces/IBancorV3.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + + Copyright 2022 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.6; +pragma experimental ABIEncoderV2; + +interface IBancorV3 { + + /** + * @dev returns the output amount when trading by providing the source amount + */ + function tradeOutputBySourceAmount( + address sourceToken, + address targetToken, + uint256 sourceAmount + ) external view returns (uint256); + + /** + * @dev returns the input amount when trading by providing the target amount + */ + function tradeInputByTargetAmount( + address sourceToken, + address targetToken, + uint256 targetAmount + ) external view returns (uint256); + +} \ No newline at end of file diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index 18c4383a45..d1fd122c53 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -39,7 +39,7 @@ "config": { "publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2BatchSampler|BalancerV2Common|BalancerV2Sampler|BancorSampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|ERC20BridgeSampler|FakeTaker|GMXSampler|IBalancer|IBalancerV2Vault|IBancor|ICurve|IGMX|IMStable|IMooniswap|IMultiBridge|IPlatypus|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|NativeOrderSampler|PlatypusSampler|SamplerUtils|ShellSampler|SmoothySampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json", + "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2BatchSampler|BalancerV2Common|BalancerV2Sampler|BancorSampler|BancorV3Sampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|ERC20BridgeSampler|FakeTaker|GMXSampler|IBalancer|IBalancerV2Vault|IBancor|IBancorV3|ICurve|IGMX|IMStable|IMooniswap|IMultiBridge|IPlatypus|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|NativeOrderSampler|PlatypusSampler|SamplerUtils|ShellSampler|SmoothySampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json", "postpublish": { "assets": [] } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts index 2a5b0c73a1..ae7d44cfe6 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -84,6 +84,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Balancer, ERC20BridgeSource.BalancerV2, ERC20BridgeSource.Bancor, + ERC20BridgeSource.BancorV3, ERC20BridgeSource.MStable, ERC20BridgeSource.Mooniswap, ERC20BridgeSource.SushiSwap, @@ -229,6 +230,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Balancer, ERC20BridgeSource.BalancerV2, // ERC20BridgeSource.Bancor, // FIXME: Bancor Buys not implemented in Sampler + ERC20BridgeSource.BancorV3, ERC20BridgeSource.MStable, ERC20BridgeSource.Mooniswap, ERC20BridgeSource.Shell, @@ -2058,6 +2060,20 @@ export const BANCOR_REGISTRY_BY_CHAIN_ID = valueByChainId( NULL_ADDRESS, ); +export const BANCORV3_NETWORK_BY_CHAIN_ID = valueByChainId( + { + [ChainId.Mainnet]: '0xeef417e1d5cc832e619ae18d2f140de2999dd4fb', + }, + NULL_ADDRESS, +); + +export const BANCORV3_NETWORK_INFO_BY_CHAIN_ID = valueByChainId( + { + [ChainId.Mainnet]: '0x8e303d296851b320e6a697bacb979d13c9d6e760', + }, + NULL_ADDRESS, +); + export const SHELL_POOLS_BY_CHAIN_ID = valueByChainId( { [ChainId.Mainnet]: { @@ -2502,6 +2518,7 @@ export const DEFAULT_GAS_SCHEDULE: Required = { } return gas; }, + [ERC20BridgeSource.BancorV3]: () => 260e3, [ERC20BridgeSource.KyberDmm]: (fillData?: FillData) => { let gas = 170e3; const path = (fillData as UniswapV2FillData).tokenAddressPath; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts index f3055a5c06..cfe21b48d7 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts @@ -385,7 +385,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder platypusFillData.tokenAddressPath, ]); break; - + case ERC20BridgeSource.BancorV3: + const bancorV3FillData = (order as OptimizedMarketBridgeOrder).fillData; + bridgeData = encoder.encode([bancorV3FillData.networkAddress, bancorFillData.path, bancor]); + break; default: throw new Error(AggregationError.NoBridgeForSource); } @@ -509,6 +512,7 @@ export const BRIDGE_ENCODERS: { [ERC20BridgeSource.MobiusMoney]: curveEncoder, // UniswapV2 like, (router, address[]) [ERC20BridgeSource.Bancor]: routerAddressPathEncoder, + [ERC20BridgeSource.BancorV3]: routerAddressPathEncoder, [ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder, [ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder, [ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts index d77ee9d5ff..da7a9a361f 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts @@ -25,6 +25,8 @@ import { AVALANCHE_TOKENS, BALANCER_V2_VAULT_ADDRESS_BY_CHAIN, BANCOR_REGISTRY_BY_CHAIN_ID, + BANCORV3_NETWORK_BY_CHAIN_ID, + BANCORV3_NETWORK_INFO_BY_CHAIN_ID, BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN, BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN, COMPOUND_API_URL_BY_CHAIN_ID, @@ -709,6 +711,36 @@ export class SamplerOperations { }); } + public getBancorV3SellQuotes( + networkAddress: string, + path: string[], + takerFillAmounts: BigNumber[], + ): SourceQuoteOperation { + return new SamplerContractOperation({ + source: ERC20BridgeSource.BancorV3, + fillData: { networkAddress, path}, + contract: this._samplerContract, + function: this._samplerContract.sampleBuysFromBancorV3, + params: [networkAddress, path, takerFillAmounts], + }); + } + + // Unimplemented + public getBancorV3BuyQuotes( + networkAddress: string, + path: string[], + makerFillAmounts: BigNumber[], + ): SourceQuoteOperation { + return new SamplerContractOperation({ + source: ERC20BridgeSource.BancorV3, + fillData: { networkAddress, path}, + contract: this._samplerContract, + function: this._samplerContract.sampleBuysFromBancorV3, + params: [networkAddress, path, makerFillAmounts], + }); + + } + public getMooniswapSellQuotes( registry: string, makerToken: string, @@ -1676,6 +1708,13 @@ export class SamplerOperations { ), ); } + case ERC20BridgeSource.BancorV3: { + return this.getBancorV3SellQuotes( + BANCORV3_NETWORK_INFO_BY_CHAIN_ID[this.chainId], + [takerToken,makerToken], + takerFillAmounts + ); + } default: throw new Error(`Unsupported sell sample source: ${source}`); } @@ -2004,6 +2043,13 @@ export class SamplerOperations { ), ); } + case ERC20BridgeSource.BancorV3: { + return this.getBancorV3SellQuotes( + BANCORV3_NETWORK_INFO_BY_CHAIN_ID[this.chainId], + [takerToken,makerToken], + makerFillAmounts + ); + } default: throw new Error(`Unsupported buy sample source: ${source}`); } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index d4f8228147..4829c4c8c2 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -66,6 +66,7 @@ export enum ERC20BridgeSource { AaveV2 = 'Aave_V2', Compound = 'Compound', Synapse = 'Synapse', + BancorV3 = 'BancorV3', // BSC only PancakeSwap = 'PancakeSwap', PancakeSwapV2 = 'PancakeSwap_V2', @@ -263,6 +264,11 @@ export interface BancorFillData extends FillData { networkAddress: string; } +export interface BancorV3FillData extends FillData { + path: string[]; + networkAddress: string; +} + export interface MooniswapFillData extends FillData { poolAddress: string; } diff --git a/packages/asset-swapper/test/artifacts.ts b/packages/asset-swapper/test/artifacts.ts index 8be87fcc48..4254073996 100644 --- a/packages/asset-swapper/test/artifacts.ts +++ b/packages/asset-swapper/test/artifacts.ts @@ -12,6 +12,7 @@ import * as BalancerV2BatchSampler from '../test/generated-artifacts/BalancerV2B import * as BalancerV2Common from '../test/generated-artifacts/BalancerV2Common.json'; import * as BalancerV2Sampler from '../test/generated-artifacts/BalancerV2Sampler.json'; import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json'; +import * as BancorV3Sampler from '../test/generated-artifacts/BancorV3Sampler.json'; import * as CompoundSampler from '../test/generated-artifacts/CompoundSampler.json'; import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json'; import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json'; @@ -22,6 +23,7 @@ import * as GMXSampler from '../test/generated-artifacts/GMXSampler.json'; import * as IBalancer from '../test/generated-artifacts/IBalancer.json'; import * as IBalancerV2Vault from '../test/generated-artifacts/IBalancerV2Vault.json'; import * as IBancor from '../test/generated-artifacts/IBancor.json'; +import * as IBancorV3 from '../test/generated-artifacts/IBancorV3.json'; import * as ICurve from '../test/generated-artifacts/ICurve.json'; import * as IGMX from '../test/generated-artifacts/IGMX.json'; import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json'; @@ -57,6 +59,7 @@ export const artifacts = { BalancerV2Common: BalancerV2Common as ContractArtifact, BalancerV2Sampler: BalancerV2Sampler as ContractArtifact, BancorSampler: BancorSampler as ContractArtifact, + BancorV3Sampler: BancorV3Sampler as ContractArtifact, CompoundSampler: CompoundSampler as ContractArtifact, CurveSampler: CurveSampler as ContractArtifact, DODOSampler: DODOSampler as ContractArtifact, @@ -83,6 +86,7 @@ export const artifacts = { IBalancer: IBalancer as ContractArtifact, IBalancerV2Vault: IBalancerV2Vault as ContractArtifact, IBancor: IBancor as ContractArtifact, + IBancorV3: IBancorV3 as ContractArtifact, ICurve: ICurve as ContractArtifact, IGMX: IGMX as ContractArtifact, IMStable: IMStable as ContractArtifact, diff --git a/packages/asset-swapper/test/wrappers.ts b/packages/asset-swapper/test/wrappers.ts index 4b8e9976f5..1be916f975 100644 --- a/packages/asset-swapper/test/wrappers.ts +++ b/packages/asset-swapper/test/wrappers.ts @@ -10,6 +10,7 @@ export * from '../test/generated-wrappers/balancer_v2_batch_sampler'; export * from '../test/generated-wrappers/balancer_v2_common'; export * from '../test/generated-wrappers/balancer_v2_sampler'; export * from '../test/generated-wrappers/bancor_sampler'; +export * from '../test/generated-wrappers/bancor_v3_sampler'; export * from '../test/generated-wrappers/compound_sampler'; export * from '../test/generated-wrappers/curve_sampler'; export * from '../test/generated-wrappers/d_o_d_o_sampler'; @@ -20,6 +21,7 @@ export * from '../test/generated-wrappers/g_m_x_sampler'; export * from '../test/generated-wrappers/i_balancer'; export * from '../test/generated-wrappers/i_balancer_v2_vault'; export * from '../test/generated-wrappers/i_bancor'; +export * from '../test/generated-wrappers/i_bancor_v3'; export * from '../test/generated-wrappers/i_curve'; export * from '../test/generated-wrappers/i_m_stable'; export * from '../test/generated-wrappers/i_mooniswap'; diff --git a/packages/asset-swapper/tsconfig.json b/packages/asset-swapper/tsconfig.json index 11b06e0537..18e504f69a 100644 --- a/packages/asset-swapper/tsconfig.json +++ b/packages/asset-swapper/tsconfig.json @@ -13,6 +13,7 @@ "test/generated-artifacts/BalancerV2Common.json", "test/generated-artifacts/BalancerV2Sampler.json", "test/generated-artifacts/BancorSampler.json", + "test/generated-artifacts/BancorV3Sampler.json", "test/generated-artifacts/CompoundSampler.json", "test/generated-artifacts/CurveSampler.json", "test/generated-artifacts/DODOSampler.json", @@ -23,6 +24,7 @@ "test/generated-artifacts/IBalancer.json", "test/generated-artifacts/IBalancerV2Vault.json", "test/generated-artifacts/IBancor.json", + "test/generated-artifacts/IBancorV3.json", "test/generated-artifacts/ICurve.json", "test/generated-artifacts/IGMX.json", "test/generated-artifacts/IMStable.json", diff --git a/packages/protocol-utils/src/transformer_utils.ts b/packages/protocol-utils/src/transformer_utils.ts index a1a90e047a..0b71a8d12a 100644 --- a/packages/protocol-utils/src/transformer_utils.ts +++ b/packages/protocol-utils/src/transformer_utils.ts @@ -138,6 +138,7 @@ export enum BridgeProtocol { BalancerV2Batch, GMX, Platypus, + BancorV3, } // tslint:enable: enum-naming