From 99f5be83783c1e4c2d8994e16293b17c398930dc Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Tue, 27 Oct 2020 15:16:09 +1000 Subject: [PATCH] chore: [asset swapper] sampler Solidity 0.6 + Bridge addresses in AS (#4) * Refactor excess interfaces * Compiles on 0.6 * Refactored into try/catch * Rebase and Refactored to v06 * Handle invalid registry in LP * Update packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol Co-authored-by: Lawrence Forman * chore: [asset-swapper] Move Bridge Addresses and Gas schedule * curve->pool * lint * Refactor to fix module load order * Move FEE Schedule * rollup: Swerve/Sushi/SnowSwap/DODO (#7) * rollup: Swerve/Sushi * DODO Rollup + Snowswap Swerve * hardcode addresses temporarily * rebase * rename to SUSHISWAP_ROUTER * CHANGELOGs * CHANGELOGs Co-authored-by: Lawrence Forman --- contracts/asset-proxy/CHANGELOG.json | 9 + .../contracts/src/bridges/SnowSwapBridge.sol | 119 ++++++ .../contracts/src/bridges/SwerveBridge.sol | 119 ++++++ contracts/asset-proxy/package.json | 2 +- contracts/asset-proxy/src/artifacts.ts | 4 + contracts/asset-proxy/src/wrappers.ts | 2 + contracts/asset-proxy/test/artifacts.ts | 4 + contracts/asset-proxy/test/wrappers.ts | 2 + contracts/asset-proxy/tsconfig.json | 4 + contracts/zero-ex/CHANGELOG.json | 9 + .../transformers/bridges/BridgeAdapter.sol | 33 +- .../bridges/mixins/MixinAdapterAddresses.sol | 6 + .../transformers/bridges/mixins/MixinDodo.sol | 97 +++++ .../bridges/mixins/MixinShell.sol | 4 +- .../bridges/mixins/MixinSushiswap.sol | 79 ++++ contracts/zero-ex/test/artifacts.ts | 4 + .../fill_quote_transformer_test.ts | 6 + contracts/zero-ex/test/wrappers.ts | 2 + contracts/zero-ex/tsconfig.json | 2 + packages/asset-swapper/CHANGELOG.json | 19 +- .../contracts/src/ApproximateBuys.sol | 6 +- .../contracts/src/BalancerSampler.sol | 44 +-- .../contracts/src/CurveSampler.sol | 4 +- .../contracts/src/DODOSampler.sol | 52 +-- .../contracts/src/DeploymentConstants.sol | 340 ++++++++++++++++++ .../contracts/src/ERC20BridgeSampler.sol | 4 +- .../contracts/src/Eth2DaiSampler.sol | 54 ++- .../contracts/src/KyberSampler.sol | 124 ++++--- .../src/LiquidityProviderSampler.sol | 56 ++- .../contracts/src/MStableSampler.sol | 49 ++- .../contracts/src/MooniswapSampler.sol | 38 +- .../contracts/src/MultiBridgeSampler.sol | 4 +- .../contracts/src/NativeOrderSampler.sol | 179 ++++++--- .../contracts/src/SamplerUtils.sol | 9 +- .../contracts/src/ShellSampler.sol | 52 ++- .../contracts/src/SushiSwapSampler.sol | 50 ++- .../contracts/src/TwoHopSampler.sol | 8 +- .../contracts/src/UniswapSampler.sol | 22 +- .../contracts/src/UniswapV2Sampler.sol | 50 ++- .../contracts/src/interfaces/IBalancer.sol | 4 +- .../contracts/src/interfaces/ICurve.sol | 4 +- .../contracts/src/interfaces/IEth2Dai.sol | 4 +- .../src/interfaces/IKyberNetwork.sol | 2 +- .../src/interfaces/ILiquidityProvider.sol | 4 +- .../interfaces/ILiquidityProviderRegistry.sol | 6 +- .../contracts/src/interfaces/IMStable.sol | 4 +- .../src/{ => interfaces}/IMooniswap.sol | 2 +- .../contracts/src/interfaces/IMultiBridge.sol | 2 +- .../contracts/src/interfaces/IShell.sol | 2 +- .../src/interfaces/IUniswapExchangeQuotes.sol | 4 +- .../src/interfaces/IUniswapV2Router01.sol | 4 +- .../contracts/test/DummyLiquidityProvider.sol | 4 +- .../test/DummyLiquidityProviderRegistry.sol | 6 +- .../contracts/test/TestERC20BridgeSampler.sol | 29 +- .../contracts/test/TestNativeOrderSampler.sol | 14 +- packages/asset-swapper/package.json | 2 +- packages/asset-swapper/src/constants.ts | 27 +- packages/asset-swapper/src/index.ts | 11 +- packages/asset-swapper/src/swap_quoter.ts | 12 +- packages/asset-swapper/src/types.ts | 28 +- .../utils/market_operation_utils/constants.ts | 231 ++++++++++-- .../src/utils/market_operation_utils/index.ts | 7 +- .../utils/market_operation_utils/orders.ts | 9 +- .../sampler_operations.ts | 4 +- packages/asset-swapper/test/artifacts.ts | 4 +- .../test/market_operation_utils_test.ts | 26 +- .../test/utils/mock_sampler_contract.ts | 33 +- packages/asset-swapper/test/wrappers.ts | 1 + packages/asset-swapper/tsconfig.json | 1 + packages/contract-addresses/CHANGELOG.json | 9 + packages/contract-addresses/addresses.json | 70 ---- packages/contract-addresses/src/index.ts | 14 - packages/migrations/src/migration.ts | 20 +- 73 files changed, 1663 insertions(+), 612 deletions(-) create mode 100644 contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol create mode 100644 contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol create mode 100644 contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinDodo.sol create mode 100644 contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinSushiswap.sol create mode 100644 packages/asset-swapper/contracts/src/DeploymentConstants.sol rename packages/asset-swapper/contracts/src/{ => interfaces}/IMooniswap.sol (97%) diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json index 501835f6ac..13870b5c1b 100644 --- a/contracts/asset-proxy/CHANGELOG.json +++ b/contracts/asset-proxy/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "3.6.0", + "changes": [ + { + "note": "Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`)", + "pr": 2707 + } + ] + }, { "version": "3.5.0", "changes": [ diff --git a/contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol b/contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol new file mode 100644 index 0000000000..614ef5017d --- /dev/null +++ b/contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol @@ -0,0 +1,119 @@ + +/* + + Copyright 2019 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.5.9; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; +import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; +import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; +import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "../interfaces/IERC20Bridge.sol"; +import "../interfaces/ICurve.sol"; + + +// solhint-disable not-rely-on-time +// solhint-disable space-after-comma +contract SnowSwapBridge is + IERC20Bridge, + IWallet, + DeploymentConstants +{ + struct SnowSwapBridgeData { + address curveAddress; + bytes4 exchangeFunctionSelector; + address fromTokenAddress; + int128 fromCoinIdx; + int128 toCoinIdx; + } + + /// @dev Callback for `ICurve`. Tries to buy `amount` of + /// `toTokenAddress` tokens by selling the entirety of the opposing asset + /// (DAI, USDC) to the Curve contract, then transfers the bought + /// tokens to `to`. + /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). + /// @param from The maker (this contract). + /// @param to The recipient of the bought tokens. + /// @param amount Minimum amount of `toTokenAddress` tokens to buy. + /// @param bridgeData The abi-encoeded "from" token address. + /// @return success The magic bytes if successful. + function bridgeTransferFrom( + address toTokenAddress, + address from, + address to, + uint256 amount, + bytes calldata bridgeData + ) + external + returns (bytes4 success) + { + // Decode the bridge data to get the SnowSwap metadata. + SnowSwapBridgeData memory data = abi.decode(bridgeData, (SnowSwapBridgeData)); + + require(toTokenAddress != data.fromTokenAddress, "SnowSwapBridge/INVALID_PAIR"); + uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); + // Grant an allowance to the exchange to spend `fromTokenAddress` token. + LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); + + // Try to sell all of this contract's `fromTokenAddress` token balance. + { + (bool didSucceed, bytes memory resultData) = + data.curveAddress.call(abi.encodeWithSelector( + data.exchangeFunctionSelector, + data.fromCoinIdx, + data.toCoinIdx, + // dx + fromTokenBalance, + // min dy + amount + )); + if (!didSucceed) { + assembly { revert(add(resultData, 32), mload(resultData)) } + } + } + + uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); + // Transfer the converted `toToken`s to `to`. + LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); + + emit ERC20BridgeTransfer( + data.fromTokenAddress, + toTokenAddress, + fromTokenBalance, + toTokenBalance, + from, + to + ); + return BRIDGE_SUCCESS; + } + + /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker + /// and sign for itself in orders. Always succeeds. + /// @return magicValue Magic success bytes, always. + function isValidSignature( + bytes32, + bytes calldata + ) + external + view + returns (bytes4 magicValue) + { + return LEGACY_WALLET_MAGIC_VALUE; + } +} diff --git a/contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol b/contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol new file mode 100644 index 0000000000..ba650f51ba --- /dev/null +++ b/contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol @@ -0,0 +1,119 @@ + +/* + + Copyright 2019 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.5.9; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; +import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; +import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; +import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "../interfaces/IERC20Bridge.sol"; +import "../interfaces/ICurve.sol"; + + +// solhint-disable not-rely-on-time +// solhint-disable space-after-comma +contract SwerveBridge is + IERC20Bridge, + IWallet, + DeploymentConstants +{ + struct SwerveBridgeData { + address curveAddress; + bytes4 exchangeFunctionSelector; + address fromTokenAddress; + int128 fromCoinIdx; + int128 toCoinIdx; + } + + /// @dev Callback for `ICurve`. Tries to buy `amount` of + /// `toTokenAddress` tokens by selling the entirety of the opposing asset + /// (DAI, USDC) to the Curve contract, then transfers the bought + /// tokens to `to`. + /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). + /// @param from The maker (this contract). + /// @param to The recipient of the bought tokens. + /// @param amount Minimum amount of `toTokenAddress` tokens to buy. + /// @param bridgeData The abi-encoeded "from" token address. + /// @return success The magic bytes if successful. + function bridgeTransferFrom( + address toTokenAddress, + address from, + address to, + uint256 amount, + bytes calldata bridgeData + ) + external + returns (bytes4 success) + { + // Decode the bridge data to get the SwerveBridgeData metadata. + SwerveBridgeData memory data = abi.decode(bridgeData, (SwerveBridgeData)); + + require(toTokenAddress != data.fromTokenAddress, "SwerveBridge/INVALID_PAIR"); + uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); + // Grant an allowance to the exchange to spend `fromTokenAddress` token. + LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); + + // Try to sell all of this contract's `fromTokenAddress` token balance. + { + (bool didSucceed, bytes memory resultData) = + data.curveAddress.call(abi.encodeWithSelector( + data.exchangeFunctionSelector, + data.fromCoinIdx, + data.toCoinIdx, + // dx + fromTokenBalance, + // min dy + amount + )); + if (!didSucceed) { + assembly { revert(add(resultData, 32), mload(resultData)) } + } + } + + uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); + // Transfer the converted `toToken`s to `to`. + LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); + + emit ERC20BridgeTransfer( + data.fromTokenAddress, + toTokenAddress, + fromTokenBalance, + toTokenBalance, + from, + to + ); + return BRIDGE_SUCCESS; + } + + /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker + /// and sign for itself in orders. Always succeeds. + /// @return magicValue Magic success bytes, always. + function isValidSignature( + bytes32, + bytes calldata + ) + external + view + returns (bytes4 magicValue) + { + return LEGACY_WALLET_MAGIC_VALUE; + } +} diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index 498a396514..897ce54aa2 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -38,7 +38,7 @@ "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" }, "config": { - "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|StaticCallProxy|SushiSwapBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json", + "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/asset-proxy/src/artifacts.ts b/contracts/asset-proxy/src/artifacts.ts index c2c15f58cf..16515d5ab6 100644 --- a/contracts/asset-proxy/src/artifacts.ts +++ b/contracts/asset-proxy/src/artifacts.ts @@ -47,8 +47,10 @@ import * as MStableBridge from '../generated-artifacts/MStableBridge.json'; import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; import * as Ownable from '../generated-artifacts/Ownable.json'; import * as ShellBridge from '../generated-artifacts/ShellBridge.json'; +import * as SnowSwapBridge from '../generated-artifacts/SnowSwapBridge.json'; import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json'; +import * as SwerveBridge from '../generated-artifacts/SwerveBridge.json'; import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json'; import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json'; import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json'; @@ -85,7 +87,9 @@ export const artifacts = { MixinGasToken: MixinGasToken as ContractArtifact, MooniswapBridge: MooniswapBridge as ContractArtifact, ShellBridge: ShellBridge as ContractArtifact, + SnowSwapBridge: SnowSwapBridge as ContractArtifact, SushiSwapBridge: SushiSwapBridge as ContractArtifact, + SwerveBridge: SwerveBridge as ContractArtifact, UniswapBridge: UniswapBridge as ContractArtifact, UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, IAssetData: IAssetData as ContractArtifact, diff --git a/contracts/asset-proxy/src/wrappers.ts b/contracts/asset-proxy/src/wrappers.ts index 8ba6a7b9a3..76df73fb0e 100644 --- a/contracts/asset-proxy/src/wrappers.ts +++ b/contracts/asset-proxy/src/wrappers.ts @@ -45,8 +45,10 @@ export * from '../generated-wrappers/mooniswap_bridge'; export * from '../generated-wrappers/multi_asset_proxy'; export * from '../generated-wrappers/ownable'; export * from '../generated-wrappers/shell_bridge'; +export * from '../generated-wrappers/snow_swap_bridge'; export * from '../generated-wrappers/static_call_proxy'; export * from '../generated-wrappers/sushi_swap_bridge'; +export * from '../generated-wrappers/swerve_bridge'; export * from '../generated-wrappers/test_bancor_bridge'; export * from '../generated-wrappers/test_chai_bridge'; export * from '../generated-wrappers/test_dex_forwarder_bridge'; diff --git a/contracts/asset-proxy/test/artifacts.ts b/contracts/asset-proxy/test/artifacts.ts index 1877c6425f..cc6dff48cc 100644 --- a/contracts/asset-proxy/test/artifacts.ts +++ b/contracts/asset-proxy/test/artifacts.ts @@ -47,8 +47,10 @@ import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json'; import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as ShellBridge from '../test/generated-artifacts/ShellBridge.json'; +import * as SnowSwapBridge from '../test/generated-artifacts/SnowSwapBridge.json'; import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; import * as SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.json'; +import * as SwerveBridge from '../test/generated-artifacts/SwerveBridge.json'; import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json'; import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json'; @@ -85,7 +87,9 @@ export const artifacts = { MixinGasToken: MixinGasToken as ContractArtifact, MooniswapBridge: MooniswapBridge as ContractArtifact, ShellBridge: ShellBridge as ContractArtifact, + SnowSwapBridge: SnowSwapBridge as ContractArtifact, SushiSwapBridge: SushiSwapBridge as ContractArtifact, + SwerveBridge: SwerveBridge as ContractArtifact, UniswapBridge: UniswapBridge as ContractArtifact, UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, IAssetData: IAssetData as ContractArtifact, diff --git a/contracts/asset-proxy/test/wrappers.ts b/contracts/asset-proxy/test/wrappers.ts index 4e2b808df5..8c511d62f1 100644 --- a/contracts/asset-proxy/test/wrappers.ts +++ b/contracts/asset-proxy/test/wrappers.ts @@ -45,8 +45,10 @@ export * from '../test/generated-wrappers/mooniswap_bridge'; export * from '../test/generated-wrappers/multi_asset_proxy'; export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/shell_bridge'; +export * from '../test/generated-wrappers/snow_swap_bridge'; export * from '../test/generated-wrappers/static_call_proxy'; export * from '../test/generated-wrappers/sushi_swap_bridge'; +export * from '../test/generated-wrappers/swerve_bridge'; export * from '../test/generated-wrappers/test_bancor_bridge'; export * from '../test/generated-wrappers/test_chai_bridge'; export * from '../test/generated-wrappers/test_dex_forwarder_bridge'; diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json index eaf2d7fd45..b3d8d879e0 100644 --- a/contracts/asset-proxy/tsconfig.json +++ b/contracts/asset-proxy/tsconfig.json @@ -45,8 +45,10 @@ "generated-artifacts/MultiAssetProxy.json", "generated-artifacts/Ownable.json", "generated-artifacts/ShellBridge.json", + "generated-artifacts/SnowSwapBridge.json", "generated-artifacts/StaticCallProxy.json", "generated-artifacts/SushiSwapBridge.json", + "generated-artifacts/SwerveBridge.json", "generated-artifacts/TestBancorBridge.json", "generated-artifacts/TestChaiBridge.json", "generated-artifacts/TestDexForwarderBridge.json", @@ -101,8 +103,10 @@ "test/generated-artifacts/MultiAssetProxy.json", "test/generated-artifacts/Ownable.json", "test/generated-artifacts/ShellBridge.json", + "test/generated-artifacts/SnowSwapBridge.json", "test/generated-artifacts/StaticCallProxy.json", "test/generated-artifacts/SushiSwapBridge.json", + "test/generated-artifacts/SwerveBridge.json", "test/generated-artifacts/TestBancorBridge.json", "test/generated-artifacts/TestChaiBridge.json", "test/generated-artifacts/TestDexForwarderBridge.json", diff --git a/contracts/zero-ex/CHANGELOG.json b/contracts/zero-ex/CHANGELOG.json index 886a6813f5..6776bd79fe 100644 --- a/contracts/zero-ex/CHANGELOG.json +++ b/contracts/zero-ex/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "0.5.0", + "changes": [ + { + "note": "Add `Swerve`, `SnowSwap`, `DODO` and `SushiSwap` into FQT", + "pr": 7 + } + ] + }, { "version": "0.4.0", "changes": [ diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol index bedd77c898..5ed51e23d6 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol @@ -22,11 +22,13 @@ pragma experimental ABIEncoderV2; import "./mixins/MixinAdapterAddresses.sol"; import "./mixins/MixinBalancer.sol"; import "./mixins/MixinCurve.sol"; +import "./mixins/MixinDodo.sol"; import "./mixins/MixinKyber.sol"; import "./mixins/MixinMooniswap.sol"; import "./mixins/MixinMStable.sol"; import "./mixins/MixinOasis.sol"; import "./mixins/MixinShell.sol"; +import "./mixins/MixinSushiswap.sol"; import "./mixins/MixinUniswap.sol"; import "./mixins/MixinUniswapV2.sol"; import "./mixins/MixinZeroExBridge.sol"; @@ -35,11 +37,13 @@ contract BridgeAdapter is MixinAdapterAddresses, MixinBalancer, MixinCurve, + MixinDodo, MixinKyber, MixinMooniswap, MixinMStable, MixinOasis, MixinShell, + MixinSushiswap, MixinUniswap, MixinUniswapV2, MixinZeroExBridge @@ -48,11 +52,15 @@ contract BridgeAdapter is address private immutable BALANCER_BRIDGE_ADDRESS; address private immutable CREAM_BRIDGE_ADDRESS; address private immutable CURVE_BRIDGE_ADDRESS; + address private immutable DODO_BRIDGE_ADDRESS; address private immutable KYBER_BRIDGE_ADDRESS; address private immutable MOONISWAP_BRIDGE_ADDRESS; address private immutable MSTABLE_BRIDGE_ADDRESS; address private immutable OASIS_BRIDGE_ADDRESS; address private immutable SHELL_BRIDGE_ADDRESS; + address private immutable SNOW_SWAP_BRIDGE_ADDRESS; + address private immutable SUSHISWAP_BRIDGE_ADDRESS; + address private immutable SWERVE_BRIDGE_ADDRESS; address private immutable UNISWAP_BRIDGE_ADDRESS; address private immutable UNISWAP_V2_BRIDGE_ADDRESS; @@ -76,11 +84,13 @@ contract BridgeAdapter is public MixinBalancer() MixinCurve() + MixinDodo(addresses) MixinKyber(addresses) MixinMooniswap(addresses) MixinMStable(addresses) MixinOasis(addresses) MixinShell(addresses) + MixinSushiswap(addresses) MixinUniswap(addresses) MixinUniswapV2(addresses) MixinZeroExBridge() @@ -92,9 +102,13 @@ contract BridgeAdapter is MSTABLE_BRIDGE_ADDRESS = addresses.mStableBridge; OASIS_BRIDGE_ADDRESS = addresses.oasisBridge; SHELL_BRIDGE_ADDRESS = addresses.shellBridge; + SUSHISWAP_BRIDGE_ADDRESS = addresses.sushiswapBridge; + SWERVE_BRIDGE_ADDRESS = addresses.swerveBridge; UNISWAP_BRIDGE_ADDRESS = addresses.uniswapBridge; UNISWAP_V2_BRIDGE_ADDRESS = addresses.uniswapV2Bridge; CREAM_BRIDGE_ADDRESS = addresses.creamBridge; + SNOW_SWAP_BRIDGE_ADDRESS = addresses.snowSwapBridge; + DODO_BRIDGE_ADDRESS = addresses.dodoBridge; } function trade( @@ -118,12 +132,20 @@ contract BridgeAdapter is "BridgeAdapter/INVALID_BRIDGE_ADDRESS" ); - if (bridgeAddress == CURVE_BRIDGE_ADDRESS) { + if (bridgeAddress == CURVE_BRIDGE_ADDRESS || + bridgeAddress == SWERVE_BRIDGE_ADDRESS || + bridgeAddress == SNOW_SWAP_BRIDGE_ADDRESS) { boughtAmount = _tradeCurve( buyToken, sellAmount, bridgeData ); + } else if (bridgeAddress == SUSHISWAP_BRIDGE_ADDRESS) { + boughtAmount = _tradeSushiswap( + buyToken, + sellAmount, + bridgeData + ); } else if (bridgeAddress == UNISWAP_V2_BRIDGE_ADDRESS) { boughtAmount = _tradeUniswapV2( buyToken, @@ -136,7 +158,8 @@ contract BridgeAdapter is sellAmount, bridgeData ); - } else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS || bridgeAddress == CREAM_BRIDGE_ADDRESS) { + } else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS || + bridgeAddress == CREAM_BRIDGE_ADDRESS) { boughtAmount = _tradeBalancer( buyToken, sellAmount, @@ -172,6 +195,12 @@ contract BridgeAdapter is sellAmount, bridgeData ); + } else if (bridgeAddress == DODO_BRIDGE_ADDRESS) { + boughtAmount = _tradeDodo( + buyToken, + sellAmount, + bridgeData + ); } else { boughtAmount = _tradeZeroExBridge( bridgeAddress, diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinAdapterAddresses.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinAdapterAddresses.sol index 33e2de618d..9268ca73bd 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinAdapterAddresses.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinAdapterAddresses.sol @@ -26,20 +26,26 @@ contract MixinAdapterAddresses address balancerBridge; address creamBridge; address curveBridge; + address dodoBridge; address kyberBridge; address mooniswapBridge; address mStableBridge; address oasisBridge; address shellBridge; + address snowSwapBridge; + address swerveBridge; + address sushiswapBridge; address uniswapBridge; address uniswapV2Bridge; // Exchanges address kyberNetworkProxy; address oasis; + address sushiswapRouter; address uniswapV2Router; address uniswapExchangeFactory; address mStable; address shell; + address dodoHelper; // Other address weth; } diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinDodo.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinDodo.sol new file mode 100644 index 0000000000..f323cf4c70 --- /dev/null +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinDodo.sol @@ -0,0 +1,97 @@ + +/* + + 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"; +import "./MixinAdapterAddresses.sol"; + +interface IDODOHelper { + + function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256); +} + + +interface IDODO { + + function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256); + + function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256); + +} + + +contract MixinDodo is + MixinAdapterAddresses +{ + using LibERC20TokenV06 for IERC20TokenV06; + + /// @dev Mainnet address of the `DOODO Helper` contract. + IDODOHelper private immutable DODO_HELPER; + + constructor(AdapterAddresses memory addresses) + public + { + DODO_HELPER = IDODOHelper(addresses.dodoHelper); + } + + function _tradeDodo( + IERC20TokenV06 /* buyToken */, + uint256 sellAmount, + bytes memory bridgeData + ) + internal + returns (uint256 boughtAmount) + { + (address fromTokenAddress, + address pool, + bool isSellBase) = abi.decode(bridgeData, (address, address, bool)); + + // Grant the Dodo pool contract an allowance to sell the first token. + IERC20TokenV06(fromTokenAddress).approveIfBelow(pool, sellAmount); + + if (isSellBase) { + // Sell the Base token directly against the contract + boughtAmount = IDODO(pool).sellBaseToken( + // amount to sell + sellAmount, + // min receive amount + 1, + new bytes(0) + ); + } else { + // Need to re-calculate the sell quote amount into buyBase + boughtAmount = DODO_HELPER.querySellQuoteToken( + pool, + sellAmount + ); + IDODO(pool).buyBaseToken( + // amount to buy + boughtAmount, + // max pay amount + sellAmount, + new bytes(0) + ); + } + + return boughtAmount; + } +} diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinShell.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinShell.sol index 11fd88599f..b99994f7c9 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinShell.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinShell.sol @@ -69,7 +69,7 @@ contract MixinShell is sellAmount ); - uint256 buyAmount = SHELL.originSwap( + boughtAmount = SHELL.originSwap( fromTokenAddress, address(buyToken), // Sell all tokens we hold. @@ -79,6 +79,6 @@ contract MixinShell is // deadline block.timestamp + 1 ); - return buyAmount; + return boughtAmount; } } diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinSushiswap.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinSushiswap.sol new file mode 100644 index 0000000000..e8bf716826 --- /dev/null +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinSushiswap.sol @@ -0,0 +1,79 @@ + +/* + + 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"; +import "./MixinAdapterAddresses.sol"; +import "./MixinUniswapV2.sol"; + +contract MixinSushiswap is + MixinAdapterAddresses +{ + using LibERC20TokenV06 for IERC20TokenV06; + + /// @dev Mainnet address of the `SushiswapRouter` contract. + IUniswapV2Router02 private immutable SUSHISWAP_ROUTER; + + constructor(AdapterAddresses memory addresses) + public + { + SUSHISWAP_ROUTER = IUniswapV2Router02(addresses.sushiswapRouter); + } + + function _tradeSushiswap( + IERC20TokenV06 buyToken, + uint256 sellAmount, + bytes memory bridgeData + ) + internal + returns (uint256 boughtAmount) + { + // solhint-disable indent + address[] memory path = abi.decode(bridgeData, (address[])); + // solhint-enable indent + + require(path.length >= 2, "SushiswapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); + require( + path[path.length - 1] == address(buyToken), + "SushiswapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN" + ); + // Grant the Uniswap router an allowance to sell the first token. + IERC20TokenV06(path[0]).approveIfBelow( + address(SUSHISWAP_ROUTER), + sellAmount + ); + + uint[] memory amounts = SUSHISWAP_ROUTER.swapExactTokensForTokens( + // Sell all tokens we hold. + sellAmount, + // Minimum buy amount. + 1, + // Convert to `buyToken` along this path. + path, + // Recipient is `this`. + address(this), + // Expires after this block. + block.timestamp + ); + return amounts[amounts.length-1]; + } +} diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts index df53980f76..eabd2dfe84 100644 --- a/contracts/zero-ex/test/artifacts.ts +++ b/contracts/zero-ex/test/artifacts.ts @@ -65,11 +65,13 @@ import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransa import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json'; import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json'; import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json'; +import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json'; import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json'; import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json'; import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json'; import * as MixinOasis from '../test/generated-artifacts/MixinOasis.json'; import * as MixinShell from '../test/generated-artifacts/MixinShell.json'; +import * as MixinSushiswap from '../test/generated-artifacts/MixinSushiswap.json'; import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json'; import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json'; import * as MixinZeroExBridge from '../test/generated-artifacts/MixinZeroExBridge.json'; @@ -176,11 +178,13 @@ export const artifacts = { MixinAdapterAddresses: MixinAdapterAddresses as ContractArtifact, MixinBalancer: MixinBalancer as ContractArtifact, MixinCurve: MixinCurve as ContractArtifact, + MixinDodo: MixinDodo as ContractArtifact, MixinKyber: MixinKyber as ContractArtifact, MixinMStable: MixinMStable as ContractArtifact, MixinMooniswap: MixinMooniswap as ContractArtifact, MixinOasis: MixinOasis as ContractArtifact, MixinShell: MixinShell as ContractArtifact, + MixinSushiswap: MixinSushiswap as ContractArtifact, MixinUniswap: MixinUniswap as ContractArtifact, MixinUniswapV2: MixinUniswapV2 as ContractArtifact, MixinZeroExBridge: MixinZeroExBridge as ContractArtifact, diff --git a/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts b/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts index 724688da44..1255f4ad83 100644 --- a/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts +++ b/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts @@ -65,10 +65,13 @@ blockchainTests.resets('FillQuoteTransformer', env => { mooniswapBridge: NULL_ADDRESS, mStableBridge: NULL_ADDRESS, oasisBridge: NULL_ADDRESS, + sushiswapBridge: NULL_ADDRESS, + swerveBridge: NULL_ADDRESS, uniswapBridge: NULL_ADDRESS, uniswapV2Bridge: NULL_ADDRESS, kyberNetworkProxy: NULL_ADDRESS, oasis: NULL_ADDRESS, + sushiswapRouter: NULL_ADDRESS, uniswapV2Router: NULL_ADDRESS, uniswapExchangeFactory: NULL_ADDRESS, mStable: NULL_ADDRESS, @@ -76,6 +79,9 @@ blockchainTests.resets('FillQuoteTransformer', env => { shellBridge: NULL_ADDRESS, shell: NULL_ADDRESS, creamBridge: NULL_ADDRESS, + dodoBridge: NULL_ADDRESS, + dodoHelper: NULL_ADDRESS, + snowSwapBridge: NULL_ADDRESS, }, ); transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync( diff --git a/contracts/zero-ex/test/wrappers.ts b/contracts/zero-ex/test/wrappers.ts index adc00601e5..bc47d3199a 100644 --- a/contracts/zero-ex/test/wrappers.ts +++ b/contracts/zero-ex/test/wrappers.ts @@ -63,11 +63,13 @@ export * from '../test/generated-wrappers/meta_transactions_feature'; export * from '../test/generated-wrappers/mixin_adapter_addresses'; export * from '../test/generated-wrappers/mixin_balancer'; export * from '../test/generated-wrappers/mixin_curve'; +export * from '../test/generated-wrappers/mixin_dodo'; export * from '../test/generated-wrappers/mixin_kyber'; export * from '../test/generated-wrappers/mixin_m_stable'; export * from '../test/generated-wrappers/mixin_mooniswap'; export * from '../test/generated-wrappers/mixin_oasis'; export * from '../test/generated-wrappers/mixin_shell'; +export * from '../test/generated-wrappers/mixin_sushiswap'; export * from '../test/generated-wrappers/mixin_uniswap'; export * from '../test/generated-wrappers/mixin_uniswap_v2'; export * from '../test/generated-wrappers/mixin_zero_ex_bridge'; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json index e75fcce22e..b45e8fae82 100644 --- a/contracts/zero-ex/tsconfig.json +++ b/contracts/zero-ex/tsconfig.json @@ -87,11 +87,13 @@ "test/generated-artifacts/MixinAdapterAddresses.json", "test/generated-artifacts/MixinBalancer.json", "test/generated-artifacts/MixinCurve.json", + "test/generated-artifacts/MixinDodo.json", "test/generated-artifacts/MixinKyber.json", "test/generated-artifacts/MixinMStable.json", "test/generated-artifacts/MixinMooniswap.json", "test/generated-artifacts/MixinOasis.json", "test/generated-artifacts/MixinShell.json", + "test/generated-artifacts/MixinSushiswap.json", "test/generated-artifacts/MixinUniswap.json", "test/generated-artifacts/MixinUniswapV2.json", "test/generated-artifacts/MixinZeroExBridge.json", diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index 0e7bb3d51b..21979c55f2 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -1,4 +1,17 @@ [ + { + "version": "4.8.0", + "changes": [ + { + "note": "Moved Bridge addresses into Asset-swapper", + "pr": 4 + }, + { + "note": "Updated Sampler to Solidity 0.6", + "pr": 4 + } + ] + }, { "timestamp": 1603487270, "version": "4.7.1", @@ -172,8 +185,12 @@ "pr": 2731 }, { - "note": "Support DODO Trade Allowed parameter to automatically disable the pool", + "note": "Support `DODO` Trade Allowed parameter to automatically disable the pool", "pr": 2732 + }, + { + "note": "Added `SwerveBridge` and `SnowSwapBridge` deployed addresses", + "pr": 7 } ], "timestamp": 1603265572 diff --git a/packages/asset-swapper/contracts/src/ApproximateBuys.sol b/packages/asset-swapper/contracts/src/ApproximateBuys.sol index 15c5e16826..e934224ad1 100644 --- a/packages/asset-swapper/contracts/src/ApproximateBuys.sol +++ b/packages/asset-swapper/contracts/src/ApproximateBuys.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; +import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol"; contract ApproximateBuys { diff --git a/packages/asset-swapper/contracts/src/BalancerSampler.sol b/packages/asset-swapper/contracts/src/BalancerSampler.sol index 8606935574..60a254fa90 100644 --- a/packages/asset-swapper/contracts/src/BalancerSampler.sol +++ b/packages/asset-swapper/contracts/src/BalancerSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; import "./interfaces/IBalancer.sol"; @@ -78,24 +78,24 @@ contract BalancerSampler { if (takerTokenAmounts[i] > _bmul(poolState.takerTokenBalance, MAX_IN_RATIO)) { break; } - (bool didSucceed, bytes memory resultData) = - poolAddress.staticcall.gas(BALANCER_CALL_GAS)( - abi.encodeWithSelector( - pool.calcOutGivenIn.selector, + try + pool.calcOutGivenIn + {gas: BALANCER_CALL_GAS} + ( poolState.takerTokenBalance, poolState.takerTokenWeight, poolState.makerTokenBalance, poolState.makerTokenWeight, takerTokenAmounts[i], poolState.swapFee - )); - uint256 buyAmount = 0; - if (didSucceed) { - buyAmount = abi.decode(resultData, (uint256)); - } else { + ) + returns (uint256 amount) + { + makerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - makerTokenAmounts[i] = buyAmount; } } @@ -136,24 +136,24 @@ contract BalancerSampler { if (makerTokenAmounts[i] > _bmul(poolState.makerTokenBalance, MAX_OUT_RATIO)) { break; } - (bool didSucceed, bytes memory resultData) = - poolAddress.staticcall.gas(BALANCER_CALL_GAS)( - abi.encodeWithSelector( - pool.calcInGivenOut.selector, + try + pool.calcInGivenOut + {gas: BALANCER_CALL_GAS} + ( poolState.takerTokenBalance, poolState.takerTokenWeight, poolState.makerTokenBalance, poolState.makerTokenWeight, makerTokenAmounts[i], poolState.swapFee - )); - uint256 sellAmount = 0; - if (didSucceed) { - sellAmount = abi.decode(resultData, (uint256)); - } else { + ) + returns (uint256 amount) + { + takerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - takerTokenAmounts[i] = sellAmount; } } diff --git a/packages/asset-swapper/contracts/src/CurveSampler.sol b/packages/asset-swapper/contracts/src/CurveSampler.sol index 36b1de99db..a560d3a508 100644 --- a/packages/asset-swapper/contracts/src/CurveSampler.sol +++ b/packages/asset-swapper/contracts/src/CurveSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; import "./interfaces/ICurve.sol"; diff --git a/packages/asset-swapper/contracts/src/DODOSampler.sol b/packages/asset-swapper/contracts/src/DODOSampler.sol index db018c4f0b..418d270456 100644 --- a/packages/asset-swapper/contracts/src/DODOSampler.sol +++ b/packages/asset-swapper/contracts/src/DODOSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "./DeploymentConstants.sol"; import "./ApproximateBuys.sol"; import "./SamplerUtils.sol"; @@ -50,6 +50,8 @@ contract DODOSampler is /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). /// @param takerTokenAmounts Taker token sell amount for each sample. + /// @return sellBase whether the bridge needs to sell the base token + /// @return pool the DODO pool address /// @return makerTokenAmounts Maker amounts bought at each taker token /// amount. function sampleSellsFromDODO( @@ -104,6 +106,8 @@ contract DODOSampler is /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). /// @param makerTokenAmounts Maker token sell amount for each sample. + /// @return sellBase whether the bridge needs to sell the base token + /// @return pool the DODO pool address /// @return takerTokenAmounts Taker amounts sold at each maker token /// amount. function sampleBuysFromDODO( @@ -167,32 +171,34 @@ contract DODOSampler is (address, address, address) ); - bool didSucceed; - bytes memory resultData; // We will get called to sell both the taker token and also to sell the maker token if (takerToken == baseToken) { // If base token then use the original query on the pool - (didSucceed, resultData) = - pool.staticcall.gas(DODO_CALL_GAS)( - abi.encodeWithSelector( - IDODO(0).querySellBaseToken.selector, - sellAmount - )); + try + IDODO(pool).querySellBaseToken + {gas: DODO_CALL_GAS} + (sellAmount) + returns (uint256 amount) + { + return amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + return 0; + } } else { // If quote token then use helper, this is less accurate - (didSucceed, resultData) = - _getDODOHelperAddress().staticcall.gas(DODO_CALL_GAS)( - abi.encodeWithSelector( - IDODOHelper(0).querySellQuoteToken.selector, - pool, - sellAmount - )); + try + IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken + {gas: DODO_CALL_GAS} + (pool, sellAmount) + returns (uint256 amount) + { + return amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + return 0; + } } - if (!didSucceed) { - return 0; - } - // solhint-disable-next-line indent - return abi.decode(resultData, (uint256)); } } diff --git a/packages/asset-swapper/contracts/src/DeploymentConstants.sol b/packages/asset-swapper/contracts/src/DeploymentConstants.sol new file mode 100644 index 0000000000..2310260162 --- /dev/null +++ b/packages/asset-swapper/contracts/src/DeploymentConstants.sol @@ -0,0 +1,340 @@ +/* + + 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; + + +contract DeploymentConstants { + + // solhint-disable separate-by-one-line-in-contract + + // Mainnet addresses /////////////////////////////////////////////////////// + /// @dev Mainnet address of the WETH contract. + address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + /// @dev Mainnet address of the KyberNetworkProxy contract. + address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x9AAb3f75489902f3a48495025729a0AF77d4b11e; + /// @dev Mainnet address of the KyberHintHandler contract. + address constant private KYBER_HINT_HANDLER_ADDRESS = 0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C; + /// @dev Mainnet address of the `UniswapExchangeFactory` contract. + address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95; + /// @dev Mainnet address of the `UniswapV2Router01` contract. + address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a; + /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract. + address constant private ETH2DAI_ADDRESS = 0x794e6e91555438aFc3ccF1c5076A74F42133d08D; + /// @dev Mainnet address of the `ERC20BridgeProxy` contract + address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0x8ED95d1746bf1E4dAb58d8ED4724f1Ef95B20Db0; + ///@dev Mainnet address of the `Dai` (multi-collateral) contract + address constant private DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + /// @dev Mainnet address of the `Chai` contract + address constant private CHAI_ADDRESS = 0x06AF07097C9Eeb7fD685c692751D5C66dB49c215; + /// @dev Mainnet address of the 0x DevUtils contract. + address constant private DEV_UTILS_ADDRESS = 0x74134CF88b21383713E096a5ecF59e297dc7f547; + /// @dev Kyber ETH pseudo-address. + address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + /// @dev Mainnet address of the dYdX contract. + address constant private DYDX_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e; + /// @dev Mainnet address of the GST2 contract + address constant private GST_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04; + /// @dev Mainnet address of the GST Collector + address constant private GST_COLLECTOR_ADDRESS = 0x000000D3b08566BE75A6DB803C03C85C0c1c5B96; + /// @dev Mainnet address of the mStable mUSD contract. + address constant private MUSD_ADDRESS = 0xe2f2a5C287993345a840Db3B0845fbC70f5935a5; + /// @dev Mainnet address of the Mooniswap Registry contract + address constant private MOONISWAP_REGISTRY = 0x71CD6666064C3A1354a3B4dca5fA1E2D3ee7D303; + /// @dev Mainnet address of the Shell contract + address constant private SHELL_CONTRACT = 0x2E703D658f8dd21709a7B458967aB4081F8D3d05; + /// @dev Mainnet address of the DODO Registry (ZOO) contract + address constant private DODO_REGISTRY = 0x3A97247DF274a17C59A3bd12735ea3FcDFb49950; + /// @dev Mainnet address of the DODO Helper contract + address constant private DODO_HELPER = 0x533dA777aeDCE766CEAe696bf90f8541A4bA80Eb; + + // // Ropsten addresses /////////////////////////////////////////////////////// + // /// @dev Mainnet address of the WETH contract. + // address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab; + // /// @dev Mainnet address of the KyberNetworkProxy contract. + // address constant private KYBER_NETWORK_PROXY_ADDRESS = 0xd719c34261e099Fdb33030ac8909d5788D3039C4; + // /// @dev Mainnet address of the `UniswapExchangeFactory` contract. + // address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0x9c83dCE8CA20E9aAF9D3efc003b2ea62aBC08351; + // /// @dev Mainnet address of the `UniswapV2Router01` contract. + // address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a; + // /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract. + // address constant private ETH2DAI_ADDRESS = address(0); + // /// @dev Mainnet address of the `ERC20BridgeProxy` contract + // address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xb344afeD348de15eb4a9e180205A2B0739628339; + // ///@dev Mainnet address of the `Dai` (multi-collateral) contract + // address constant private DAI_ADDRESS = address(0); + // /// @dev Mainnet address of the `Chai` contract + // address constant private CHAI_ADDRESS = address(0); + // /// @dev Mainnet address of the 0x DevUtils contract. + // address constant private DEV_UTILS_ADDRESS = 0xC812AF3f3fBC62F76ea4262576EC0f49dB8B7f1c; + // /// @dev Kyber ETH pseudo-address. + // address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + // /// @dev Mainnet address of the dYdX contract. + // address constant private DYDX_ADDRESS = address(0); + // /// @dev Mainnet address of the GST2 contract + // address constant private GST_ADDRESS = address(0); + // /// @dev Mainnet address of the GST Collector + // address constant private GST_COLLECTOR_ADDRESS = address(0); + // /// @dev Mainnet address of the mStable mUSD contract. + // address constant private MUSD_ADDRESS = 0x4E1000616990D83e56f4b5fC6CC8602DcfD20459; + + // // Rinkeby addresses /////////////////////////////////////////////////////// + // /// @dev Mainnet address of the WETH contract. + // address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab; + // /// @dev Mainnet address of the KyberNetworkProxy contract. + // address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x0d5371e5EE23dec7DF251A8957279629aa79E9C5; + // /// @dev Mainnet address of the `UniswapExchangeFactory` contract. + // address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36; + // /// @dev Mainnet address of the `UniswapV2Router01` contract. + // address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a; + // /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract. + // address constant private ETH2DAI_ADDRESS = address(0); + // /// @dev Mainnet address of the `ERC20BridgeProxy` contract + // address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xA2AA4bEFED748Fba27a3bE7Dfd2C4b2c6DB1F49B; + // ///@dev Mainnet address of the `Dai` (multi-collateral) contract + // address constant private DAI_ADDRESS = address(0); + // /// @dev Mainnet address of the `Chai` contract + // address constant private CHAI_ADDRESS = address(0); + // /// @dev Mainnet address of the 0x DevUtils contract. + // address constant private DEV_UTILS_ADDRESS = 0x46B5BC959e8A754c0256FFF73bF34A52Ad5CdfA9; + // /// @dev Kyber ETH pseudo-address. + // address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + // /// @dev Mainnet address of the dYdX contract. + // address constant private DYDX_ADDRESS = address(0); + // /// @dev Mainnet address of the GST2 contract + // address constant private GST_ADDRESS = address(0); + // /// @dev Mainnet address of the GST Collector + // address constant private GST_COLLECTOR_ADDRESS = address(0); + // /// @dev Mainnet address of the mStable mUSD contract. + // address constant private MUSD_ADDRESS = address(0); + + // // Kovan addresses ///////////////////////////////////////////////////////// + // /// @dev Kovan address of the WETH contract. + // address constant private WETH_ADDRESS = 0xd0A1E359811322d97991E03f863a0C30C2cF029C; + // /// @dev Kovan address of the KyberNetworkProxy contract. + // address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D; + // /// @dev Kovan address of the `UniswapExchangeFactory` contract. + // address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30; + // /// @dev Kovan address of the `UniswapV2Router01` contract. + // address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a; + // /// @dev Kovan address of the Eth2Dai `MatchingMarket` contract. + // address constant private ETH2DAI_ADDRESS = 0xe325acB9765b02b8b418199bf9650972299235F4; + // /// @dev Kovan address of the `ERC20BridgeProxy` contract + // address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0x3577552C1Fb7A44aD76BeEB7aB53251668A21F8D; + // /// @dev Kovan address of the `Chai` contract + // address constant private CHAI_ADDRESS = address(0); + // /// @dev Kovan address of the `Dai` (multi-collateral) contract + // address constant private DAI_ADDRESS = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa; + // /// @dev Kovan address of the 0x DevUtils contract. + // address constant private DEV_UTILS_ADDRESS = 0x9402639A828BdF4E9e4103ac3B69E1a6E522eB59; + // /// @dev Kyber ETH pseudo-address. + // address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + // /// @dev Kovan address of the dYdX contract. + // address constant private DYDX_ADDRESS = address(0); + // /// @dev Kovan address of the GST2 contract + // address constant private GST_ADDRESS = address(0); + // /// @dev Kovan address of the GST Collector + // address constant private GST_COLLECTOR_ADDRESS = address(0); + // /// @dev Mainnet address of the mStable mUSD contract. + // address constant private MUSD_ADDRESS = address(0); + + /// @dev Overridable way to get the `KyberNetworkProxy` address. + /// @return kyberAddress The `IKyberNetworkProxy` address. + function _getKyberNetworkProxyAddress() + virtual + internal + view + returns (address kyberAddress) + { + return KYBER_NETWORK_PROXY_ADDRESS; + } + + /// @dev Overridable way to get the `KyberHintHandler` address. + /// @return hintHandlerAddress The `IKyberHintHandler` address. + function _getKyberHintHandlerAddress() + virtual + internal + view + returns (address hintHandlerAddress) + { + return KYBER_HINT_HANDLER_ADDRESS; + } + + /// @dev Overridable way to get the WETH address. + /// @return wethAddress The WETH address. + function _getWethAddress() + internal + view + returns (address wethAddress) + { + return WETH_ADDRESS; + } + + /// @dev Overridable way to get the `UniswapExchangeFactory` address. + /// @return uniswapAddress The `UniswapExchangeFactory` address. + function _getUniswapExchangeFactoryAddress() + virtual + internal + view + returns (address uniswapAddress) + { + return UNISWAP_EXCHANGE_FACTORY_ADDRESS; + } + + /// @dev Overridable way to get the `UniswapV2Router01` address. + /// @return uniswapRouterAddress The `UniswapV2Router01` address. + function _getUniswapV2Router01Address() + virtual + internal + view + returns (address uniswapRouterAddress) + { + return UNISWAP_V2_ROUTER_01_ADDRESS; + } + + /// @dev An overridable way to retrieve the Eth2Dai `MatchingMarket` contract. + /// @return eth2daiAddress The Eth2Dai `MatchingMarket` contract. + function _getEth2DaiAddress() + virtual + internal + view + returns (address eth2daiAddress) + { + return ETH2DAI_ADDRESS; + } + + /// @dev An overridable way to retrieve the `ERC20BridgeProxy` contract. + /// @return erc20BridgeProxyAddress The `ERC20BridgeProxy` contract. + function _getERC20BridgeProxyAddress() + internal + view + returns (address erc20BridgeProxyAddress) + { + return ERC20_BRIDGE_PROXY_ADDRESS; + } + + /// @dev An overridable way to retrieve the `Dai` contract. + /// @return daiAddress The `Dai` contract. + function _getDaiAddress() + internal + view + returns (address daiAddress) + { + return DAI_ADDRESS; + } + + /// @dev An overridable way to retrieve the `Chai` contract. + /// @return chaiAddress The `Chai` contract. + function _getChaiAddress() + internal + view + returns (address chaiAddress) + { + return CHAI_ADDRESS; + } + + /// @dev An overridable way to retrieve the 0x `DevUtils` contract address. + /// @return devUtils The 0x `DevUtils` contract address. + function _getDevUtilsAddress() + internal + view + returns (address devUtils) + { + return DEV_UTILS_ADDRESS; + } + + /// @dev Overridable way to get the DyDx contract. + /// @return dydxAddress exchange The DyDx exchange contract. + function _getDydxAddress() + internal + view + returns (address dydxAddress) + { + return DYDX_ADDRESS; + } + + /// @dev An overridable way to retrieve the GST2 contract address. + /// @return gst The GST contract. + function _getGstAddress() + internal + view + returns (address gst) + { + return GST_ADDRESS; + } + + /// @dev An overridable way to retrieve the GST Collector address. + /// @return collector The GST collector address. + function _getGstCollectorAddress() + internal + view + returns (address collector) + { + return GST_COLLECTOR_ADDRESS; + } + + /// @dev An overridable way to retrieve the mStable mUSD address. + /// @return musd The mStable mUSD address. + function _getMUsdAddress() + internal + view + returns (address musd) + { + return MUSD_ADDRESS; + } + + /// @dev An overridable way to retrieve the Mooniswap registry address. + /// @return registry The Mooniswap registry address. + function _getMooniswapAddress() + internal + view + returns (address) + { + return MOONISWAP_REGISTRY; + } + + /// @dev An overridable way to retrieve the Shell contract address. + /// @return registry The Shell contract address. + function _getShellAddress() + internal + view + returns (address registry) + { + return SHELL_CONTRACT; + } + + /// @dev An overridable way to retrieve the DODO Registry contract address. + /// @return registry The DODO Registry contract address. + function _getDODORegistryAddress() + internal + view + returns (address registry) + { + return DODO_REGISTRY; + } + + /// @dev An overridable way to retrieve the DODO Helper contract address. + /// @return registry The DODO Helper contract address. + function _getDODOHelperAddress() + internal + view + returns (address registry) + { + return DODO_HELPER; + } +} diff --git a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol index dee441ec68..8902b83313 100644 --- a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol +++ b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; import "./BalancerSampler.sol"; diff --git a/packages/asset-swapper/contracts/src/Eth2DaiSampler.sol b/packages/asset-swapper/contracts/src/Eth2DaiSampler.sol index 216cdfc707..10630266b3 100644 --- a/packages/asset-swapper/contracts/src/Eth2DaiSampler.sol +++ b/packages/asset-swapper/contracts/src/Eth2DaiSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "./DeploymentConstants.sol"; import "./interfaces/IEth2Dai.sol"; import "./SamplerUtils.sol"; @@ -50,23 +50,17 @@ contract Eth2DaiSampler is uint256 numSamples = takerTokenAmounts.length; makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - _getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)( - abi.encodeWithSelector( - IEth2Dai(0).getBuyAmount.selector, - makerToken, - takerToken, - takerTokenAmounts[i] - )); - uint256 buyAmount = 0; - if (didSucceed) { - buyAmount = abi.decode(resultData, (uint256)); - } - // Exit early if the amount is too high for the source to serve - if (buyAmount == 0) { + try + IEth2Dai(_getEth2DaiAddress()).getBuyAmount + {gas: ETH2DAI_CALL_GAS} + (makerToken, takerToken, takerTokenAmounts[i]) + returns (uint256 amount) + { + makerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - makerTokenAmounts[i] = buyAmount; } } @@ -89,23 +83,17 @@ contract Eth2DaiSampler is uint256 numSamples = makerTokenAmounts.length; takerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - _getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)( - abi.encodeWithSelector( - IEth2Dai(0).getPayAmount.selector, - takerToken, - makerToken, - makerTokenAmounts[i] - )); - uint256 sellAmount = 0; - if (didSucceed) { - sellAmount = abi.decode(resultData, (uint256)); - } - // Exit early if the amount is too high for the source to serve - if (sellAmount == 0) { + try + IEth2Dai(_getEth2DaiAddress()).getPayAmount + {gas: ETH2DAI_CALL_GAS} + (takerToken, makerToken, makerTokenAmounts[i]) + returns (uint256 amount) + { + takerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - takerTokenAmounts[i] = sellAmount; } } } diff --git a/packages/asset-swapper/contracts/src/KyberSampler.sol b/packages/asset-swapper/contracts/src/KyberSampler.sol index 17293f32ff..d4d334ca61 100644 --- a/packages/asset-swapper/contracts/src/KyberSampler.sol +++ b/packages/asset-swapper/contracts/src/KyberSampler.sol @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "./DeploymentConstants.sol"; import "./interfaces/IKyberNetwork.sol"; import "./ApproximateBuys.sol"; import "./SamplerUtils.sol"; @@ -109,52 +109,66 @@ contract KyberSampler is // All other reserves should be ignored with this hint bytes32[] memory selectedReserves = new bytes32[](1); selectedReserves[0] = reserveId; + uint256[] memory emptySplits = new uint256[](0); - bool didSucceed; - bytes memory resultData; if (takerToken == _getWethAddress()) { // ETH to Token - (didSucceed, resultData) = - address(kyberHint).staticcall.gas(KYBER_CALL_GAS)( - abi.encodeWithSelector( - IKyberHintHandler(0).buildEthToTokenHint.selector, + try + kyberHint.buildEthToTokenHint + {gas: KYBER_CALL_GAS} + ( makerToken, IKyberHintHandler.TradeType.MaskIn, selectedReserves, - new uint256[](0))); + emptySplits + ) + returns (bytes memory result) + { + return result; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + } } else if (makerToken == _getWethAddress()) { // Token to ETH - (didSucceed, resultData) = - address(kyberHint).staticcall.gas(KYBER_CALL_GAS)( - abi.encodeWithSelector( - IKyberHintHandler(0).buildTokenToEthHint.selector, + try + kyberHint.buildTokenToEthHint + {gas: KYBER_CALL_GAS} + ( takerToken, IKyberHintHandler.TradeType.MaskIn, selectedReserves, - new uint256[](0))); + emptySplits + ) + returns (bytes memory result) + { + return result; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + } + } else { // Token to Token // We use the same reserve both ways - (didSucceed, resultData) = - address(kyberHint).staticcall.gas(KYBER_CALL_GAS)( - abi.encodeWithSelector( - IKyberHintHandler(0).buildTokenToTokenHint.selector, + try + kyberHint.buildTokenToTokenHint + {gas: KYBER_CALL_GAS} + ( takerToken, IKyberHintHandler.TradeType.MaskIn, selectedReserves, - new uint256[](0), + emptySplits, makerToken, IKyberHintHandler.TradeType.MaskIn, selectedReserves, - new uint256[](0) + emptySplits ) - ); + returns (bytes memory result) + { + return result; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + } } - // If successful decode the hint - if (didSucceed) { - hint = abi.decode(resultData, (bytes)); - } - return hint; } function _sampleSellForApproximateBuyFromKyber( @@ -164,25 +178,22 @@ contract KyberSampler is ) private view - returns (uint256 buyAmount) + returns (uint256) { (address makerToken, bytes memory hint) = abi.decode(makerTokenData, (address, bytes)); (address takerToken, ) = abi.decode(takerTokenData, (address, bytes)); - (bool success, bytes memory resultData) = - address(this).staticcall(abi.encodeWithSelector( - this.sampleSellFromKyberNetwork.selector, - hint, - takerToken, - makerToken, - sellAmount - )); - if (!success) { + try + this.sampleSellFromKyberNetwork + (hint, takerToken, makerToken, sellAmount) + returns (uint256 amount) + { + return amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. return 0; } - // solhint-disable-next-line indent - return abi.decode(resultData, (uint256)); } function sampleSellFromKyberNetwork( @@ -200,31 +211,30 @@ contract KyberSampler is return 0; } - (bool didSucceed, bytes memory resultData) = - _getKyberNetworkProxyAddress().staticcall.gas(KYBER_CALL_GAS)( - abi.encodeWithSelector( - IKyberNetworkProxy(0).getExpectedRateAfterFee.selector, + try + IKyberNetworkProxy(_getKyberNetworkProxyAddress()).getExpectedRateAfterFee + {gas: KYBER_CALL_GAS} + ( takerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : takerToken, makerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : makerToken, takerTokenAmount, 0, // fee hint - )); - uint256 rate = 0; - if (didSucceed) { - (rate) = abi.decode(resultData, (uint256)); - } else { + ) + returns (uint256 rate) + { + uint256 makerTokenDecimals = _getTokenDecimals(makerToken); + uint256 takerTokenDecimals = _getTokenDecimals(takerToken); + makerTokenAmount = + rate * + takerTokenAmount * + 10 ** makerTokenDecimals / + 10 ** takerTokenDecimals / + 10 ** 18; + return makerTokenAmount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. return 0; } - - uint256 makerTokenDecimals = _getTokenDecimals(makerToken); - uint256 takerTokenDecimals = _getTokenDecimals(takerToken); - makerTokenAmount = - rate * - takerTokenAmount * - 10 ** makerTokenDecimals / - 10 ** takerTokenDecimals / - 10 ** 18; - return makerTokenAmount; } } diff --git a/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol b/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol index 0c74b521d7..a64fb347fb 100644 --- a/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol +++ b/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; +import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; import "./interfaces/ILiquidityProvider.sol"; import "./interfaces/ILiquidityProviderRegistry.sol"; import "./ApproximateBuys.sol"; @@ -66,23 +66,17 @@ contract LiquidityProviderSampler is } for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - providerAddress.staticcall.gas(DEFAULT_CALL_GAS)( - abi.encodeWithSelector( - ILiquidityProvider(0).getSellQuote.selector, - takerToken, - makerToken, - takerTokenAmounts[i] - )); - uint256 buyAmount = 0; - if (didSucceed) { - buyAmount = abi.decode(resultData, (uint256)); - } - // Exit early if the amount is too high for the source to serve - if (buyAmount == 0) { + try + ILiquidityProvider(providerAddress).getSellQuote + {gas: DEFAULT_CALL_GAS} + (takerToken, makerToken, takerTokenAmounts[i]) + returns (uint256 amount) + { + makerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - makerTokenAmounts[i] = buyAmount; } } @@ -136,14 +130,15 @@ contract LiquidityProviderSampler is if (registryAddress == address(0)) { return address(0); } + bytes memory callData = abi.encodeWithSelector( - ILiquidityProviderRegistry(0).getLiquidityProviderForMarket.selector, + ILiquidityProviderRegistry.getLiquidityProviderForMarket.selector, takerToken, makerToken ); (bool didSucceed, bytes memory returnData) = registryAddress.staticcall(callData); if (didSucceed && returnData.length == 32) { - return LibBytes.readAddress(returnData, 12); + return LibBytesV06.readAddress(returnData, 12); } } @@ -160,19 +155,16 @@ contract LiquidityProviderSampler is abi.decode(takerTokenData, (address, address)); (address makerToken) = abi.decode(makerTokenData, (address)); - (bool success, bytes memory resultData) = - address(this).staticcall(abi.encodeWithSelector( - this.sampleSellsFromLiquidityProviderRegistry.selector, - plpRegistryAddress, - takerToken, - makerToken, - _toSingleValueArray(sellAmount) - )); - if (!success) { + try + this.sampleSellsFromLiquidityProviderRegistry + {gas: DEFAULT_CALL_GAS} + (plpRegistryAddress, takerToken, makerToken, _toSingleValueArray(sellAmount)) + returns (uint256[] memory amounts, address) + { + return amounts[0]; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. return 0; } - // solhint-disable-next-line indent - (uint256[] memory amounts, ) = abi.decode(resultData, (uint256[], address)); - return amounts[0]; } } diff --git a/packages/asset-swapper/contracts/src/MStableSampler.sol b/packages/asset-swapper/contracts/src/MStableSampler.sol index 205f86b91d..a8b767f547 100644 --- a/packages/asset-swapper/contracts/src/MStableSampler.sol +++ b/packages/asset-swapper/contracts/src/MStableSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,11 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; +import "./DeploymentConstants.sol"; import "./interfaces/IMStable.sol"; import "./ApproximateBuys.sol"; import "./SamplerUtils.sol"; @@ -54,23 +53,17 @@ contract MStableSampler is makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - address(_getMUsdAddress()).staticcall.gas(DEFAULT_CALL_GAS)( - abi.encodeWithSelector( - IMStable(0).getSwapOutput.selector, - takerToken, - makerToken, - takerTokenAmounts[i] - )); - uint256 buyAmount = 0; - if (didSucceed) { - (, , buyAmount) = abi.decode(resultData, (bool, string, uint256)); - } - // Exit early if the amount is too high for the source to serve - if (buyAmount == 0) { + try + IMStable(_getMUsdAddress()).getSwapOutput + {gas: DEFAULT_CALL_GAS} + (takerToken, makerToken, takerTokenAmounts[i]) + returns (bool, string memory, uint256 amount) + { + makerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - makerTokenAmounts[i] = buyAmount; } } @@ -112,17 +105,15 @@ contract MStableSampler is abi.decode(takerTokenData, (address)); (address makerToken) = abi.decode(makerTokenData, (address)); - (bool success, bytes memory resultData) = - address(this).staticcall(abi.encodeWithSelector( - this.sampleSellsFromMStable.selector, - takerToken, - makerToken, - _toSingleValueArray(sellAmount) - )); - if (!success) { + try + this.sampleSellsFromMStable + (takerToken, makerToken, _toSingleValueArray(sellAmount)) + returns (uint256[] memory amounts) + { + return amounts[0]; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. return 0; } - // solhint-disable-next-line indent - return abi.decode(resultData, (uint256[]))[0]; } } diff --git a/packages/asset-swapper/contracts/src/MooniswapSampler.sol b/packages/asset-swapper/contracts/src/MooniswapSampler.sol index 0c19e7d72b..f212092cb6 100644 --- a/packages/asset-swapper/contracts/src/MooniswapSampler.sol +++ b/packages/asset-swapper/contracts/src/MooniswapSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,11 +16,11 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "./IMooniswap.sol"; +import "./DeploymentConstants.sol"; +import "./interfaces/IMooniswap.sol"; import "./ApproximateBuys.sol"; import "./SamplerUtils.sol"; @@ -37,6 +37,7 @@ contract MooniswapSampler is /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). /// @param takerTokenAmounts Taker token sell amount for each sample. + /// @return pool The contract address for the pool /// @return makerTokenAmounts Maker amounts bought at each taker token /// amount. function sampleSellsFromMooniswap( @@ -80,7 +81,7 @@ contract MooniswapSampler is ) public view - returns (uint256 makerTokenAmount) + returns (uint256) { // Find the pool for the pair. IMooniswap pool = IMooniswap( @@ -88,26 +89,26 @@ contract MooniswapSampler is ); // If there is no pool then return early if (address(pool) == address(0)) { - return makerTokenAmount; + return 0; } uint256 poolBalance = mooniswapTakerToken == address(0) ? address(pool).balance - : IERC20Token(mooniswapTakerToken).balanceOf(address(pool)); + : IERC20TokenV06(mooniswapTakerToken).balanceOf(address(pool)); // If the pool balance is smaller than the sell amount // don't sample to avoid multiplication overflow in buys if (poolBalance < takerTokenAmount) { - return makerTokenAmount; + return 0; } - (bool didSucceed, bytes memory resultData) = - address(pool).staticcall.gas(MOONISWAP_CALL_GAS)( - abi.encodeWithSelector( - pool.getReturn.selector, - mooniswapTakerToken, - mooniswapMakerToken, - takerTokenAmount - )); - if (didSucceed) { - makerTokenAmount = abi.decode(resultData, (uint256)); + try + pool.getReturn + {gas: MOONISWAP_CALL_GAS} + (mooniswapTakerToken, mooniswapMakerToken, takerTokenAmount) + returns (uint256 amount) + { + return amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + return 0; } } @@ -115,6 +116,7 @@ contract MooniswapSampler is /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). /// @param makerTokenAmounts Maker token sell amount for each sample. + /// @return pool The contract address for the pool /// @return takerTokenAmounts Taker amounts sold at each maker token /// amount. function sampleBuysFromMooniswap( diff --git a/packages/asset-swapper/contracts/src/MultiBridgeSampler.sol b/packages/asset-swapper/contracts/src/MultiBridgeSampler.sol index 2be713dd8b..e9254449b8 100644 --- a/packages/asset-swapper/contracts/src/MultiBridgeSampler.sol +++ b/packages/asset-swapper/contracts/src/MultiBridgeSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; import "./interfaces/IMultiBridge.sol"; diff --git a/packages/asset-swapper/contracts/src/NativeOrderSampler.sol b/packages/asset-swapper/contracts/src/NativeOrderSampler.sol index c1a36cc0b4..83d8139471 100644 --- a/packages/asset-swapper/contracts/src/NativeOrderSampler.sol +++ b/packages/asset-swapper/contracts/src/NativeOrderSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,21 +16,107 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; +import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; +import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol"; +import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; +import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; +interface IExchange { + + /// @dev V3 Order structure. + struct Order { + // Address that created the order. + address makerAddress; + // Address that is allowed to fill the order. + // If set to 0, any address is allowed to fill the order. + address takerAddress; + // Address that will recieve fees when order is filled. + address feeRecipientAddress; + // Address that is allowed to call Exchange contract methods that affect this order. + // If set to 0, any address is allowed to call these methods. + address senderAddress; + // Amount of makerAsset being offered by maker. Must be greater than 0. + uint256 makerAssetAmount; + // Amount of takerAsset being bid on by maker. Must be greater than 0. + uint256 takerAssetAmount; + // Fee paid to feeRecipient by maker when order is filled. + uint256 makerFee; + // Fee paid to feeRecipient by taker when order is filled. + uint256 takerFee; + // Timestamp in seconds at which order expires. + uint256 expirationTimeSeconds; + // Arbitrary number to facilitate uniqueness of the order's hash. + uint256 salt; + // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. + // The leading bytes4 references the id of the asset proxy. + bytes makerAssetData; + // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. + // The leading bytes4 references the id of the asset proxy. + bytes takerAssetData; + // Encoded data that can be decoded by a specified proxy contract when transferring makerFeeAsset. + // The leading bytes4 references the id of the asset proxy. + bytes makerFeeAssetData; + // Encoded data that can be decoded by a specified proxy contract when transferring takerFeeAsset. + // The leading bytes4 references the id of the asset proxy. + bytes takerFeeAssetData; + } + + // A valid order remains fillable until it is expired, fully filled, or cancelled. + // An order's status is unaffected by external factors, like account balances. + enum OrderStatus { + INVALID, // Default value + INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount + INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount + FILLABLE, // Order is fillable + EXPIRED, // Order has already expired + FULLY_FILLED, // Order is fully filled + CANCELLED // Order has been cancelled + } + + /// @dev Order information returned by `getOrderInfo()`. + struct OrderInfo { + OrderStatus orderStatus; // Status that describes order's validity and fillability. + bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash). + uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled. + } + + /// @dev Gets information about an order: status, hash, and amount filled. + /// @param order Order to gather information on. + /// @return orderInfo Information about the order and its state. + function getOrderInfo(IExchange.Order calldata order) + external + view + returns (IExchange.OrderInfo memory orderInfo); + + /// @dev Verifies that a hash has been signed by the given signer. + /// @param hash Any 32-byte hash. + /// @param signature Proof that the hash has been signed by signer. + /// @return isValid `true` if the signature is valid for the given hash and signer. + function isValidHashSignature( + bytes32 hash, + address signerAddress, + bytes calldata signature + ) + external + view + returns (bool isValid); + + /// @dev Gets an asset proxy. + /// @param assetProxyId Id of the asset proxy. + /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered. + function getAssetProxy(bytes4 assetProxyId) + external + view + returns (address); +} + contract NativeOrderSampler { - using LibSafeMath for uint256; - using LibBytes for bytes; + using LibSafeMathV06 for uint256; + using LibBytesV06 for bytes; /// @dev The Exchange ERC20Proxy ID. bytes4 private constant ERC20_ASSET_PROXY_ID = 0xf47261b0; @@ -45,8 +131,8 @@ contract NativeOrderSampler { view returns (uint256, uint256) { - uint256 fromTokenDecimals = LibERC20Token.decimals(makerTokenAddress); - uint256 toTokenDecimals = LibERC20Token.decimals(takerTokenAddress); + uint256 fromTokenDecimals = LibERC20TokenV06.compatDecimals(IERC20TokenV06(makerTokenAddress)); + uint256 toTokenDecimals = LibERC20TokenV06.compatDecimals(IERC20TokenV06(takerTokenAddress)); return (fromTokenDecimals, toTokenDecimals); } @@ -59,7 +145,7 @@ contract NativeOrderSampler { /// @return orderFillableTakerAssetAmounts How much taker asset can be filled /// by each order in `orders`. function getOrderFillableTakerAssetAmounts( - LibOrder.Order[] memory orders, + IExchange.Order[] memory orders, bytes[] memory orderSignatures, IExchange exchange ) @@ -69,21 +155,21 @@ contract NativeOrderSampler { { orderFillableTakerAssetAmounts = new uint256[](orders.length); for (uint256 i = 0; i != orders.length; i++) { - // solhint-disable indent - (bool didSucceed, bytes memory resultData) = - address(this) - .staticcall - .gas(DEFAULT_CALL_GAS) - (abi.encodeWithSelector( - this.getOrderFillableTakerAmount.selector, + try + this.getOrderFillableTakerAmount + {gas: DEFAULT_CALL_GAS} + ( orders[i], orderSignatures[i], exchange - )); - // solhint-enable indent - orderFillableTakerAssetAmounts[i] = didSucceed - ? abi.decode(resultData, (uint256)) - : 0; + ) + returns (uint256 amount) + { + orderFillableTakerAssetAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + orderFillableTakerAssetAmounts[i] = 0; + } } } @@ -95,7 +181,7 @@ contract NativeOrderSampler { /// @return orderFillableMakerAssetAmounts How much maker asset can be filled /// by each order in `orders`. function getOrderFillableMakerAssetAmounts( - LibOrder.Order[] memory orders, + IExchange.Order[] memory orders, bytes[] memory orderSignatures, IExchange exchange ) @@ -112,7 +198,7 @@ contract NativeOrderSampler { // convert them to maker asset amounts. for (uint256 i = 0; i < orders.length; ++i) { if (orderFillableMakerAssetAmounts[i] != 0) { - orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil( + orderFillableMakerAssetAmounts[i] = LibMathV06.getPartialAmountCeil( orderFillableMakerAssetAmounts[i], orders[i].takerAssetAmount, orders[i].makerAssetAmount @@ -124,10 +210,11 @@ contract NativeOrderSampler { /// @dev Get the fillable taker amount of an order, taking into account /// order state, maker fees, and maker balances. function getOrderFillableTakerAmount( - LibOrder.Order memory order, + IExchange.Order memory order, bytes memory signature, IExchange exchange ) + virtual public view returns (uint256 fillableTakerAmount) @@ -139,27 +226,27 @@ contract NativeOrderSampler { return 0; } - LibOrder.OrderInfo memory orderInfo = exchange.getOrderInfo(order); - if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) { + IExchange.OrderInfo memory orderInfo = exchange.getOrderInfo(order); + if (orderInfo.orderStatus != IExchange.OrderStatus.FILLABLE) { return 0; } if (!exchange.isValidHashSignature(orderInfo.orderHash, order.makerAddress, signature)) { return 0; } address spender = exchange.getAssetProxy(ERC20_ASSET_PROXY_ID); - IERC20Token makerToken = _getTokenFromERC20AssetData(order.makerAssetData); - if (makerToken == IERC20Token(0)) { + IERC20TokenV06 makerToken = _getTokenFromERC20AssetData(order.makerAssetData); + if (makerToken == IERC20TokenV06(0)) { return 0; } - IERC20Token makerFeeToken = order.makerFee > 0 + IERC20TokenV06 makerFeeToken = order.makerFee > 0 ? _getTokenFromERC20AssetData(order.makerFeeAssetData) - : IERC20Token(0); + : IERC20TokenV06(0); uint256 remainingTakerAmount = order.takerAssetAmount .safeSub(orderInfo.orderTakerAssetFilledAmount); fillableTakerAmount = remainingTakerAmount; // The total fillable maker amount is the remaining fillable maker amount // PLUS maker fees, if maker fees are denominated in the maker token. - uint256 totalFillableMakerAmount = LibMath.safeGetPartialAmountFloor( + uint256 totalFillableMakerAmount = LibMathV06.safeGetPartialAmountFloor( remainingTakerAmount, order.takerAssetAmount, makerFeeToken == makerToken @@ -168,14 +255,14 @@ contract NativeOrderSampler { ); // The spendable amount of maker tokens (by the maker) is the lesser of // the maker's balance and the allowance they've granted to the ERC20Proxy. - uint256 spendableMakerAmount = LibSafeMath.min256( + uint256 spendableMakerAmount = LibSafeMathV06.min256( makerToken.balanceOf(order.makerAddress), makerToken.allowance(order.makerAddress, spender) ); // Scale the fillable taker amount by the ratio of the maker's // spendable maker amount over the total fillable maker amount. if (spendableMakerAmount < totalFillableMakerAmount) { - fillableTakerAmount = LibMath.getPartialAmountCeil( + fillableTakerAmount = LibMathV06.getPartialAmountCeil( spendableMakerAmount, totalFillableMakerAmount, remainingTakerAmount @@ -183,15 +270,15 @@ contract NativeOrderSampler { } // If the maker fee is denominated in another token, constrain // the fillable taker amount by how much the maker can pay of that token. - if (makerFeeToken != makerToken && makerFeeToken != IERC20Token(0)) { - uint256 spendableExtraMakerFeeAmount = LibSafeMath.min256( + if (makerFeeToken != makerToken && makerFeeToken != IERC20TokenV06(0)) { + uint256 spendableExtraMakerFeeAmount = LibSafeMathV06.min256( makerFeeToken.balanceOf(order.makerAddress), makerFeeToken.allowance(order.makerAddress, spender) ); if (spendableExtraMakerFeeAmount < order.makerFee) { - fillableTakerAmount = LibSafeMath.min256( + fillableTakerAmount = LibSafeMathV06.min256( fillableTakerAmount, - LibMath.getPartialAmountCeil( + LibMathV06.getPartialAmountCeil( spendableExtraMakerFeeAmount, order.makerFee, remainingTakerAmount @@ -204,16 +291,16 @@ contract NativeOrderSampler { function _getTokenFromERC20AssetData(bytes memory assetData) private pure - returns (IERC20Token token) + returns (IERC20TokenV06 token) { if (assetData.length == 0) { - return IERC20Token(address(0)); + return IERC20TokenV06(address(0)); } if (assetData.length != 36 || assetData.readBytes4(0) != ERC20_ASSET_PROXY_ID) { - return IERC20Token(address(0)); + return IERC20TokenV06(address(0)); } - return IERC20Token(assetData.readAddress(16)); + return IERC20TokenV06(assetData.readAddress(16)); } } diff --git a/packages/asset-swapper/contracts/src/SamplerUtils.sol b/packages/asset-swapper/contracts/src/SamplerUtils.sol index 01c5dbbdb8..8c661b003b 100644 --- a/packages/asset-swapper/contracts/src/SamplerUtils.sol +++ b/packages/asset-swapper/contracts/src/SamplerUtils.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; +import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; contract SamplerUtils { @@ -28,11 +28,12 @@ contract SamplerUtils { /// @param tokenAddress Address of the token. /// @return decimals The decimal places for the token. function _getTokenDecimals(address tokenAddress) + virtual internal view returns (uint8 decimals) { - return LibERC20Token.decimals(tokenAddress); + return LibERC20TokenV06.compatDecimals(IERC20TokenV06(tokenAddress)); } function _toSingleValueArray(uint256 v) diff --git a/packages/asset-swapper/contracts/src/ShellSampler.sol b/packages/asset-swapper/contracts/src/ShellSampler.sol index 9642211a29..5eb3b2a887 100644 --- a/packages/asset-swapper/contracts/src/ShellSampler.sol +++ b/packages/asset-swapper/contracts/src/ShellSampler.sol @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "./DeploymentConstants.sol"; import "./interfaces/IShell.sol"; contract ShellSampler is @@ -48,23 +48,17 @@ contract ShellSampler is makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - address(_getShellAddress()).staticcall.gas(DEFAULT_CALL_GAS)( - abi.encodeWithSelector( - IShell(0).viewOriginSwap.selector, - takerToken, - makerToken, - takerTokenAmounts[i] - )); - uint256 buyAmount = 0; - if (didSucceed) { - buyAmount = abi.decode(resultData, (uint256)); - } - // Exit early if the amount is too high for the source to serve - if (buyAmount == 0) { + try + IShell(_getShellAddress()).viewOriginSwap + {gas: DEFAULT_CALL_GAS} + (takerToken, makerToken, takerTokenAmounts[i]) + returns (uint256 amount) + { + makerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - makerTokenAmounts[i] = buyAmount; } } @@ -88,23 +82,17 @@ contract ShellSampler is takerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - address(_getShellAddress()).staticcall.gas(DEFAULT_CALL_GAS)( - abi.encodeWithSelector( - IShell(0).viewTargetSwap.selector, - takerToken, - makerToken, - makerTokenAmounts[i] - )); - uint256 sellAmount = 0; - if (didSucceed) { - sellAmount = abi.decode(resultData, (uint256)); - } - // Exit early if the amount is too high for the source to serve - if (sellAmount == 0) { + try + IShell(_getShellAddress()).viewTargetSwap + {gas: DEFAULT_CALL_GAS} + (takerToken, makerToken, makerTokenAmounts[i]) + returns (uint256 amount) + { + takerTokenAmounts[i] = amount; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - takerTokenAmounts[i] = sellAmount; } } } diff --git a/packages/asset-swapper/contracts/src/SushiSwapSampler.sol b/packages/asset-swapper/contracts/src/SushiSwapSampler.sol index 1239d2a579..ec747c486f 100644 --- a/packages/asset-swapper/contracts/src/SushiSwapSampler.sol +++ b/packages/asset-swapper/contracts/src/SushiSwapSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "./DeploymentConstants.sol"; import "./interfaces/IUniswapV2Router01.sol"; @@ -47,21 +47,17 @@ contract SushiSwapSampler is uint256 numSamples = takerTokenAmounts.length; makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - router.staticcall.gas(SUSHISWAP_CALL_GAS)( - abi.encodeWithSelector( - IUniswapV2Router01(0).getAmountsOut.selector, - takerTokenAmounts[i], - path - )); - uint256 buyAmount = 0; - if (didSucceed) { - // solhint-disable-next-line indent - buyAmount = abi.decode(resultData, (uint256[]))[path.length - 1]; - } else { + try + IUniswapV2Router01(router).getAmountsOut + {gas: SUSHISWAP_CALL_GAS} + (takerTokenAmounts[i], path) + returns (uint256[] memory amounts) + { + makerTokenAmounts[i] = amounts[path.length - 1]; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - makerTokenAmounts[i] = buyAmount; } } @@ -83,21 +79,17 @@ contract SushiSwapSampler is uint256 numSamples = makerTokenAmounts.length; takerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - router.staticcall.gas(SUSHISWAP_CALL_GAS)( - abi.encodeWithSelector( - IUniswapV2Router01(0).getAmountsIn.selector, - makerTokenAmounts[i], - path - )); - uint256 sellAmount = 0; - if (didSucceed) { - // solhint-disable-next-line indent - sellAmount = abi.decode(resultData, (uint256[]))[0]; - } else { + try + IUniswapV2Router01(router).getAmountsIn + {gas: SUSHISWAP_CALL_GAS} + (makerTokenAmounts[i], path) + returns (uint256[] memory amounts) + { + takerTokenAmounts[i] = amounts[0]; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - takerTokenAmounts[i] = sellAmount; } } } diff --git a/packages/asset-swapper/contracts/src/TwoHopSampler.sol b/packages/asset-swapper/contracts/src/TwoHopSampler.sol index 9f03a2f2f7..114af5be38 100644 --- a/packages/asset-swapper/contracts/src/TwoHopSampler.sol +++ b/packages/asset-swapper/contracts/src/TwoHopSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,14 +16,14 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; +import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; contract TwoHopSampler { - using LibBytes for bytes; + using LibBytesV06 for bytes; struct HopInfo { uint256 sourceIndex; diff --git a/packages/asset-swapper/contracts/src/UniswapSampler.sol b/packages/asset-swapper/contracts/src/UniswapSampler.sol index 313512ef5f..df3ac38b0c 100644 --- a/packages/asset-swapper/contracts/src/UniswapSampler.sol +++ b/packages/asset-swapper/contracts/src/UniswapSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,19 +16,25 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; +import "./DeploymentConstants.sol"; import "./interfaces/IUniswapExchangeQuotes.sol"; import "./SamplerUtils.sol"; +interface IUniswapExchangeFactory { + + /// @dev Get the exchange for a token. + /// @param tokenAddress The address of the token contract. + function getExchange(address tokenAddress) + external + view + returns (address); +} + + contract UniswapSampler is DeploymentConstants, SamplerUtils diff --git a/packages/asset-swapper/contracts/src/UniswapV2Sampler.sol b/packages/asset-swapper/contracts/src/UniswapV2Sampler.sol index 5ae117c458..e49624dbad 100644 --- a/packages/asset-swapper/contracts/src/UniswapV2Sampler.sol +++ b/packages/asset-swapper/contracts/src/UniswapV2Sampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,10 +16,10 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "./DeploymentConstants.sol"; import "./interfaces/IUniswapV2Router01.sol"; @@ -45,21 +45,17 @@ contract UniswapV2Sampler is uint256 numSamples = takerTokenAmounts.length; makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - _getUniswapV2Router01Address().staticcall.gas(UNISWAPV2_CALL_GAS)( - abi.encodeWithSelector( - IUniswapV2Router01(0).getAmountsOut.selector, - takerTokenAmounts[i], - path - )); - uint256 buyAmount = 0; - if (didSucceed) { - // solhint-disable-next-line indent - buyAmount = abi.decode(resultData, (uint256[]))[path.length - 1]; - } else { + try + IUniswapV2Router01(_getUniswapV2Router01Address()).getAmountsOut + {gas: UNISWAPV2_CALL_GAS} + (takerTokenAmounts[i], path) + returns (uint256[] memory amounts) + { + makerTokenAmounts[i] = amounts[path.length - 1]; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - makerTokenAmounts[i] = buyAmount; } } @@ -79,21 +75,17 @@ contract UniswapV2Sampler is uint256 numSamples = makerTokenAmounts.length; takerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { - (bool didSucceed, bytes memory resultData) = - _getUniswapV2Router01Address().staticcall.gas(UNISWAPV2_CALL_GAS)( - abi.encodeWithSelector( - IUniswapV2Router01(0).getAmountsIn.selector, - makerTokenAmounts[i], - path - )); - uint256 sellAmount = 0; - if (didSucceed) { - // solhint-disable-next-line indent - sellAmount = abi.decode(resultData, (uint256[]))[0]; - } else { + try + IUniswapV2Router01(_getUniswapV2Router01Address()).getAmountsIn + {gas: UNISWAPV2_CALL_GAS} + (makerTokenAmounts[i], path) + returns (uint256[] memory amounts) + { + takerTokenAmounts[i] = amounts[0]; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. break; } - takerTokenAmounts[i] = sellAmount; } } } diff --git a/packages/asset-swapper/contracts/src/interfaces/IBalancer.sol b/packages/asset-swapper/contracts/src/interfaces/IBalancer.sol index 78082fb88a..ce67311354 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IBalancer.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IBalancer.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IBalancer { diff --git a/packages/asset-swapper/contracts/src/interfaces/ICurve.sol b/packages/asset-swapper/contracts/src/interfaces/ICurve.sol index 13a0d75ea0..acb756c09f 100644 --- a/packages/asset-swapper/contracts/src/interfaces/ICurve.sol +++ b/packages/asset-swapper/contracts/src/interfaces/ICurve.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; // solhint-disable func-name-mixedcase diff --git a/packages/asset-swapper/contracts/src/interfaces/IEth2Dai.sol b/packages/asset-swapper/contracts/src/interfaces/IEth2Dai.sol index f4b38ca9c6..b02df6f3db 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IEth2Dai.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IEth2Dai.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IEth2Dai { diff --git a/packages/asset-swapper/contracts/src/interfaces/IKyberNetwork.sol b/packages/asset-swapper/contracts/src/interfaces/IKyberNetwork.sol index ebfd45e912..2e3a35cd42 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IKyberNetwork.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IKyberNetwork.sol @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; // Keepin everything together interface IKyberNetwork { diff --git a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol b/packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol index b88c23a251..c07a8ebfff 100644 --- a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol +++ b/packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface ILiquidityProvider { diff --git a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol b/packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol index 22a39299b1..0ad8c4cb6f 100644 --- a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol +++ b/packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface ILiquidityProviderRegistry { @@ -25,7 +25,7 @@ interface ILiquidityProviderRegistry { /// (takerToken, makerToken), reverting if the pool does not exist. /// @param takerToken Taker asset managed by liquidity provider. /// @param makerToken Maker asset managed by liquidity provider. - /// @return Address of the liquidity provider. + /// @return providerAddress Address of the liquidity provider. function getLiquidityProviderForMarket( address takerToken, address makerToken diff --git a/packages/asset-swapper/contracts/src/interfaces/IMStable.sol b/packages/asset-swapper/contracts/src/interfaces/IMStable.sol index ee2909d3ee..9671f6d82c 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IMStable.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IMStable.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IMStable { diff --git a/packages/asset-swapper/contracts/src/IMooniswap.sol b/packages/asset-swapper/contracts/src/interfaces/IMooniswap.sol similarity index 97% rename from packages/asset-swapper/contracts/src/IMooniswap.sol rename to packages/asset-swapper/contracts/src/interfaces/IMooniswap.sol index bfec7c9871..9af74fbfd9 100644 --- a/packages/asset-swapper/contracts/src/IMooniswap.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IMooniswap.sol @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IMooniswapRegistry { diff --git a/packages/asset-swapper/contracts/src/interfaces/IMultiBridge.sol b/packages/asset-swapper/contracts/src/interfaces/IMultiBridge.sol index 9c3ad44217..bb69aa41ec 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IMultiBridge.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IMultiBridge.sol @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IMultiBridge { diff --git a/packages/asset-swapper/contracts/src/interfaces/IShell.sol b/packages/asset-swapper/contracts/src/interfaces/IShell.sol index 61caf5ceb3..bfe052b9c6 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IShell.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IShell.sol @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IShell { diff --git a/packages/asset-swapper/contracts/src/interfaces/IUniswapExchangeQuotes.sol b/packages/asset-swapper/contracts/src/interfaces/IUniswapExchangeQuotes.sol index 2c0dc600a4..34f6acc225 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IUniswapExchangeQuotes.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IUniswapExchangeQuotes.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IUniswapExchangeQuotes { diff --git a/packages/asset-swapper/contracts/src/interfaces/IUniswapV2Router01.sol b/packages/asset-swapper/contracts/src/interfaces/IUniswapV2Router01.sol index b13ce3b67b..a198011239 100644 --- a/packages/asset-swapper/contracts/src/interfaces/IUniswapV2Router01.sol +++ b/packages/asset-swapper/contracts/src/interfaces/IUniswapV2Router01.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -16,7 +16,7 @@ */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; interface IUniswapV2Router01 { diff --git a/packages/asset-swapper/contracts/test/DummyLiquidityProvider.sol b/packages/asset-swapper/contracts/test/DummyLiquidityProvider.sol index fb7d44b9f4..22eb6ee86c 100644 --- a/packages/asset-swapper/contracts/test/DummyLiquidityProvider.sol +++ b/packages/asset-swapper/contracts/test/DummyLiquidityProvider.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; @@ -35,4 +35,4 @@ contract DummyLiquidityProvider { takerTokenAmount = buyAmount + 1; } -} \ No newline at end of file +} diff --git a/packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol b/packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol index e7e1244425..a45aed5e59 100644 --- a/packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol +++ b/packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; @@ -26,7 +26,7 @@ contract DummyLiquidityProviderRegistry /// @dev Returns the address of pool for a market given market (xAsset, yAsset), or reverts if pool does not exist. /// @param xToken First asset managed by pool. /// @param yToken Second asset managed by pool. - /// @return Address of pool. + /// @return poolAddress Address of pool. function getLiquidityProviderForMarket( address xToken, address yToken @@ -41,4 +41,4 @@ contract DummyLiquidityProviderRegistry "Registry/MARKET_PAIR_NOT_SET" ); } -} \ No newline at end of file +} diff --git a/packages/asset-swapper/contracts/test/TestERC20BridgeSampler.sol b/packages/asset-swapper/contracts/test/TestERC20BridgeSampler.sol index bf190e8707..35dfb013ba 100644 --- a/packages/asset-swapper/contracts/test/TestERC20BridgeSampler.sol +++ b/packages/asset-swapper/contracts/test/TestERC20BridgeSampler.sol @@ -1,6 +1,6 @@ /* - Copyright 2019 ZeroEx Intl. + 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. @@ -15,12 +15,9 @@ limitations under the License. */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "../src/ERC20BridgeSampler.sol"; import "../src/interfaces/IEth2Dai.sol"; import "../src/interfaces/IKyberNetwork.sol"; @@ -128,6 +125,7 @@ contract TestERC20BridgeSamplerUniswapExchange is function getEthToTokenInputPrice( uint256 ethSold ) + override external view returns (uint256 tokensBought) @@ -145,6 +143,7 @@ contract TestERC20BridgeSamplerUniswapExchange is function getEthToTokenOutputPrice( uint256 tokensBought ) + override external view returns (uint256 ethSold) @@ -162,6 +161,7 @@ contract TestERC20BridgeSamplerUniswapExchange is function getTokenToEthInputPrice( uint256 tokensSold ) + override external view returns (uint256 ethBought) @@ -179,6 +179,7 @@ contract TestERC20BridgeSamplerUniswapExchange is function getTokenToEthOutputPrice( uint256 ethBought ) + override external view returns (uint256 tokensSold) @@ -203,6 +204,7 @@ contract TestERC20BridgeSamplerUniswapV2Router01 is // Deterministic `IUniswapV2Router01.getAmountsOut()`. function getAmountsOut(uint256 amountIn, address[] calldata path) + override external view returns (uint256[] memory amounts) @@ -223,6 +225,7 @@ contract TestERC20BridgeSamplerUniswapV2Router01 is // Deterministic `IUniswapV2Router01.getAmountsInt()`. function getAmountsIn(uint256 amountOut, address[] calldata path) + override external view returns (uint256[] memory amounts) @@ -333,6 +336,7 @@ contract TestERC20BridgeSamplerKyberNetwork is } function _getKyberNetworkProxyAddress() + override internal view returns (address) @@ -341,6 +345,7 @@ contract TestERC20BridgeSamplerKyberNetwork is } function _getKyberHintHandlerAddress() + override internal view returns (address) @@ -362,6 +367,7 @@ contract TestERC20BridgeSamplerEth2Dai is address payToken, uint256 payAmount ) + override external view returns (uint256 buyAmount) @@ -381,6 +387,7 @@ contract TestERC20BridgeSamplerEth2Dai is address buyToken, uint256 buyAmount ) + override external view returns (uint256 payAmount) @@ -414,6 +421,7 @@ contract TestERC20BridgeSamplerUniswapExchangeFactory is // `IUniswapExchangeFactory.getExchange()`. function getExchange(address tokenAddress) + override external view returns (address) @@ -432,7 +440,7 @@ contract TestERC20BridgeSampler is TestERC20BridgeSamplerEth2Dai public eth2Dai; TestERC20BridgeSamplerKyberNetwork public kyber; - uint8 private constant MAX_ORDER_STATUS = uint8(LibOrder.OrderStatus.CANCELLED) + 1; + uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1; constructor() public ERC20BridgeSampler() { uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory(); @@ -450,10 +458,11 @@ contract TestERC20BridgeSampler is // Overridden to return deterministic states. function getOrderFillableTakerAmount( - LibOrder.Order memory order, + IExchange.Order memory order, bytes memory, IExchange ) + override public view returns (uint256 fillableTakerAmount) @@ -463,6 +472,7 @@ contract TestERC20BridgeSampler is // Overriden to return deterministic decimals. function _getTokenDecimals(address tokenAddress) + override internal view returns (uint8 decimals) @@ -472,6 +482,7 @@ contract TestERC20BridgeSampler is // Overriden to point to a custom contract. function _getEth2DaiAddress() + override internal view returns (address eth2daiAddress) @@ -481,6 +492,7 @@ contract TestERC20BridgeSampler is // Overriden to point to a custom contract. function _getUniswapExchangeFactoryAddress() + override internal view returns (address uniswapAddress) @@ -490,6 +502,7 @@ contract TestERC20BridgeSampler is // Overriden to point to a custom contract. function _getUniswapV2Router01Address() + override internal view returns (address uniswapV2RouterAddress) @@ -499,6 +512,7 @@ contract TestERC20BridgeSampler is // Overriden to point to a custom contract. function _getKyberNetworkProxyAddress() + override internal view returns (address kyberAddress) @@ -508,6 +522,7 @@ contract TestERC20BridgeSampler is // Overriden to point to a custom contract. function _getKyberHintHandlerAddress() + override internal view returns (address kyberAddress) diff --git a/packages/asset-swapper/contracts/test/TestNativeOrderSampler.sol b/packages/asset-swapper/contracts/test/TestNativeOrderSampler.sol index 90b23e9d94..ebebd210d0 100644 --- a/packages/asset-swapper/contracts/test/TestNativeOrderSampler.sol +++ b/packages/asset-swapper/contracts/test/TestNativeOrderSampler.sol @@ -15,11 +15,9 @@ limitations under the License. */ -pragma solidity ^0.5.9; +pragma solidity ^0.6; pragma experimental ABIEncoderV2; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "../src/NativeOrderSampler.sol"; @@ -43,7 +41,7 @@ contract TestNativeOrderSamplerToken { contract TestNativeOrderSampler is NativeOrderSampler { - uint8 private constant MAX_ORDER_STATUS = uint8(LibOrder.OrderStatus.CANCELLED) + 1; + uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1; bytes32 private constant VALID_SIGNATURE_HASH = keccak256(hex"01"); function createTokens(uint256 count) @@ -78,17 +76,17 @@ contract TestNativeOrderSampler is } // IExchange.getOrderInfo() - function getOrderInfo(LibOrder.Order calldata order) + function getOrderInfo(IExchange.Order calldata order) external pure - returns (LibOrder.OrderInfo memory orderInfo) + returns (IExchange.OrderInfo memory orderInfo) { // The order salt determines everything. orderInfo.orderHash = keccak256(abi.encode(order.salt)); if (uint8(order.salt) == 0xFF) { - orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED; + orderInfo.orderStatus = IExchange.OrderStatus.FULLY_FILLED; } else { - orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE; + orderInfo.orderStatus = IExchange.OrderStatus.FILLABLE; } // The expiration time is the filled taker asset amount. orderInfo.orderTakerAssetFilledAmount = order.expirationTimeSeconds; diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index 04db2cba1e..79bcfa09f1 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -38,7 +38,7 @@ "config": { "publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json", + "abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json", "postpublish": { "assets": [] } diff --git a/packages/asset-swapper/src/constants.ts b/packages/asset-swapper/src/constants.ts index d4686e9923..3fd5145b37 100644 --- a/packages/asset-swapper/src/constants.ts +++ b/packages/asset-swapper/src/constants.ts @@ -1,3 +1,4 @@ +import { ChainId } from '@0x/contract-addresses'; import { BigNumber, logUtils } from '@0x/utils'; import { @@ -42,7 +43,7 @@ const PROTOCOL_FEE_MULTIPLIER = new BigNumber(70000); const MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE = 0.5; const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = { - chainId: MAINNET_CHAIN_ID, + chainId: ChainId.Mainnet, orderRefreshIntervalMs: 10000, // 10 seconds ...DEFAULT_ORDER_PRUNER_OPTS, samplerGasLimit: 250e6, @@ -95,6 +96,21 @@ export const DEFAULT_INFO_LOGGER: LogFunction = (obj, msg) => export const DEFAULT_WARNING_LOGGER: LogFunction = (obj, msg) => logUtils.warn(`${msg ? `${msg}: ` : ''}${JSON.stringify(obj)}`); +// This feature flag allows us to merge the price-aware RFQ pricing +// project while still controlling when to activate the feature. We plan to do some +// data analysis work and address some of the issues with maker fillable amounts +// in later milestones. Once the feature is fully rolled out and is providing value +// and we have assessed that there is no user impact, we will proceed in cleaning up +// the feature flag. When that time comes, follow this PR to "undo" the feature flag: +// https://github.com/0xProject/0x-monorepo/pull/2735 +export const IS_PRICE_AWARE_RFQ_ENABLED: boolean = false; + +export { + BRIDGE_ADDRESSES_BY_CHAIN, + DEFAULT_FEE_SCHEDULE, + DEFAULT_GAS_SCHEDULE, +} from './utils/market_operation_utils/constants'; + export const constants = { ETH_GAS_STATION_API_URL, PROTOCOL_FEE_MULTIPLIER, @@ -122,12 +138,3 @@ export const constants = { DEFAULT_INFO_LOGGER, DEFAULT_WARNING_LOGGER, }; - -// This feature flag allows us to merge the price-aware RFQ pricing -// project while still controlling when to activate the feature. We plan to do some -// data analysis work and address some of the issues with maker fillable amounts -// in later milestones. Once the feature is fully rolled out and is providing value -// and we have assessed that there is no user impact, we will proceed in cleaning up -// the feature flag. When that time comes, follow this PR to "undo" the feature flag: -// https://github.com/0xProject/0x-monorepo/pull/2735 -export const IS_PRICE_AWARE_RFQ_ENABLED: boolean = false; diff --git a/packages/asset-swapper/src/index.ts b/packages/asset-swapper/src/index.ts index eaf2d911c0..24fb8cfc97 100644 --- a/packages/asset-swapper/src/index.ts +++ b/packages/asset-swapper/src/index.ts @@ -88,6 +88,7 @@ export { getSwapMinBuyAmount } from './quote_consumers/utils'; export { SwapQuoter } from './swap_quoter'; export { AffiliateFee, + AssetSwapperContractAddresses, CalldataInfo, ExchangeProxyContractOpts, ExchangeProxyRefundReceiver, @@ -119,7 +120,11 @@ export { SwapQuoterRfqtOpts, } from './types'; export { affiliateFeeUtils } from './utils/affiliate_fee_utils'; -export { SOURCE_FLAGS } from './utils/market_operation_utils/constants'; +export { + BRIDGE_ADDRESSES_BY_CHAIN, + DEFAULT_GAS_SCHEDULE, + SOURCE_FLAGS, +} from './utils/market_operation_utils/constants'; export { Parameters, SamplerContractCall, @@ -150,13 +155,13 @@ export { NativeCollapsedFill, NativeFillData, OptimizedMarketOrder, + SnowSwapFillData, + SnowSwapInfo, SourceInfo, SourceQuoteOperation, SushiSwapFillData, SwerveFillData, SwerveInfo, - SnowSwapFillData, - SnowSwapInfo, TokenAdjacencyGraph, UniswapV2FillData, } from './utils/market_operation_utils/types'; diff --git a/packages/asset-swapper/src/swap_quoter.ts b/packages/asset-swapper/src/swap_quoter.ts index e6c5513100..9e18f33265 100644 --- a/packages/asset-swapper/src/swap_quoter.ts +++ b/packages/asset-swapper/src/swap_quoter.ts @@ -1,4 +1,4 @@ -import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; +import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; import { DevUtilsContract } from '@0x/contract-wrappers'; import { schemas } from '@0x/json-schemas'; import { assetDataUtils, SignedOrder } from '@0x/order-utils'; @@ -8,8 +8,9 @@ import { BlockParamLiteral, SupportedProvider, ZeroExProvider } from 'ethereum-t import * as _ from 'lodash'; import { artifacts } from './artifacts'; -import { constants, IS_PRICE_AWARE_RFQ_ENABLED } from './constants'; +import { BRIDGE_ADDRESSES_BY_CHAIN, constants, IS_PRICE_AWARE_RFQ_ENABLED } from './constants'; import { + AssetSwapperContractAddresses, CalculateSwapQuoteOpts, LiquidityForTakerMakerAssetDataPair, MarketBuySwapQuote, @@ -48,7 +49,7 @@ export class SwapQuoter { public readonly expiryBufferMs: number; public readonly chainId: number; public readonly permittedOrderFeeTypes: Set; - private readonly _contractAddresses: ContractAddresses; + private readonly _contractAddresses: AssetSwapperContractAddresses; private readonly _protocolFeeUtils: ProtocolFeeUtils; private readonly _swapQuoteCalculator: SwapQuoteCalculator; private readonly _devUtilsContract: DevUtilsContract; @@ -178,7 +179,10 @@ export class SwapQuoter { this.permittedOrderFeeTypes = permittedOrderFeeTypes; this._rfqtOptions = rfqt; - this._contractAddresses = options.contractAddresses || getContractAddressesForChainOrThrow(chainId); + this._contractAddresses = options.contractAddresses || { + ...getContractAddressesForChainOrThrow(chainId), + ...BRIDGE_ADDRESSES_BY_CHAIN[chainId], + }; this._devUtilsContract = new DevUtilsContract(this._contractAddresses.devUtils, provider); this._protocolFeeUtils = ProtocolFeeUtils.getInstance( constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS, diff --git a/packages/asset-swapper/src/types.ts b/packages/asset-swapper/src/types.ts index 4eaf8adde2..bb56d54c59 100644 --- a/packages/asset-swapper/src/types.ts +++ b/packages/asset-swapper/src/types.ts @@ -1,3 +1,4 @@ +import { ChainId } from '@0x/contract-addresses'; import { BlockParam, ContractAddresses, GethCallOverrides } from '@0x/contract-wrappers'; import { TakerRequestQueryParams } from '@0x/quote-server'; import { SignedOrder } from '@0x/types'; @@ -282,6 +283,8 @@ export interface SwapQuoterRfqtOpts { infoLogger?: LogFunction; } +export type AssetSwapperContractAddresses = ContractAddresses & BridgeContractAddresses; + /** * chainId: The ethereum chain id. Defaults to 1 (mainnet). * orderRefreshIntervalMs: The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s). @@ -290,11 +293,11 @@ export interface SwapQuoterRfqtOpts { * samplerGasLimit: The gas limit used when querying the sampler contract. Defaults to 36e6 */ export interface SwapQuoterOpts extends OrderPrunerOpts { - chainId: number; + chainId: ChainId; orderRefreshIntervalMs: number; expiryBufferMs: number; ethereumRpcUrl?: string; - contractAddresses?: ContractAddresses; + contractAddresses?: AssetSwapperContractAddresses; samplerGasLimit?: number; liquidityProviderRegistryAddress?: string; multiBridgeAddress?: string; @@ -380,3 +383,24 @@ export interface SamplerOverrides { } export type Omit = Pick>; +/** + * The Contract addresses of the deployed Bridges + */ +export interface BridgeContractAddresses { + uniswapBridge: string; + uniswapV2Bridge: string; + eth2DaiBridge: string; + kyberBridge: string; + curveBridge: string; + multiBridge: string; + balancerBridge: string; + bancorBridge: string; + mStableBridge: string; + mooniswapBridge: string; + sushiswapBridge: string; + shellBridge: string; + dodoBridge: string; + creamBridge: string; + swerveBridge: string; + snowswapBridge: string; +} 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 620169ee50..2c06f2c4e2 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -1,33 +1,51 @@ +import { ChainId } from '@0x/contract-addresses'; import { BigNumber } from '@0x/utils'; +import { BridgeContractAddresses } from '../../types'; + import { SourceFilters } from './source_filters'; -import { CurveFunctionSelectors, CurveInfo, ERC20BridgeSource, GetMarketOrdersOpts } from './types'; +import { + CurveFillData, + CurveFunctionSelectors, + CurveInfo, + DODOFillData, + ERC20BridgeSource, + FeeSchedule, + FillData, + GetMarketOrdersOpts, + MultiHopFillData, + SushiSwapFillData, + UniswapV2FillData, +} from './types'; // tslint:disable: custom-no-magic-numbers no-bitwise /** * Valid sources for market sell. */ -export const SELL_SOURCE_FILTER = new SourceFilters([ - ERC20BridgeSource.Native, - ERC20BridgeSource.Uniswap, - ERC20BridgeSource.UniswapV2, - ERC20BridgeSource.Eth2Dai, - ERC20BridgeSource.Kyber, - ERC20BridgeSource.Curve, - ERC20BridgeSource.Balancer, - // Bancor is sampled off-chain, but this list should only include on-chain sources (used in ERC20BridgeSampler) - // ERC20BridgeSource.Bancor, - ERC20BridgeSource.MStable, - ERC20BridgeSource.Mooniswap, - ERC20BridgeSource.Swerve, - ERC20BridgeSource.SnowSwap, - ERC20BridgeSource.SushiSwap, - ERC20BridgeSource.Shell, - ERC20BridgeSource.MultiHop, - ERC20BridgeSource.Dodo, - ERC20BridgeSource.Cream, -]); +export const SELL_SOURCE_FILTER = new SourceFilters( + [ + ERC20BridgeSource.Native, + ERC20BridgeSource.Uniswap, + ERC20BridgeSource.UniswapV2, + ERC20BridgeSource.Eth2Dai, + ERC20BridgeSource.Kyber, + ERC20BridgeSource.Curve, + ERC20BridgeSource.Balancer, + // Bancor is sampled off-chain, but this list should only include on-chain sources (used in ERC20BridgeSampler) + // ERC20BridgeSource.Bancor, + ERC20BridgeSource.MStable, + ERC20BridgeSource.Mooniswap, + ERC20BridgeSource.Swerve, + ERC20BridgeSource.SnowSwap, + ERC20BridgeSource.SushiSwap, + ERC20BridgeSource.Shell, + ERC20BridgeSource.MultiHop, + ERC20BridgeSource.Dodo, + ERC20BridgeSource.Cream, + ], + [ERC20BridgeSource.MultiBridge], +); /** * Valid sources for market buy. @@ -55,22 +73,10 @@ export const BUY_SOURCE_FILTER = new SourceFilters( [ERC20BridgeSource.MultiBridge], ); -export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = { - // tslint:disable-next-line: custom-no-magic-numbers - runLimit: 2 ** 15, - excludedSources: [], - excludedFeeSources: [], - includedSources: [], - bridgeSlippage: 0.005, - maxFallbackSlippage: 0.05, - numSamples: 13, - sampleDistributionBase: 1.05, - feeSchedule: {}, - gasSchedule: {}, - exchangeProxyOverhead: () => ZERO_AMOUNT, - allowFallback: true, - shouldGenerateQuoteReport: false, -}; +/** + * 0x Protocol Fee Multiplier + */ +export const PROTOCOL_FEE_MULTIPLIER = new BigNumber(70000); /** * Sources to poll for ETH fee price estimates. @@ -283,3 +289,154 @@ export const ONE_SECOND_MS = 1000; export const NULL_BYTES = '0x'; export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; export const COMPARISON_PRICE_DECIMALS = 5; + +const EMPTY_BRIDGE_ADDRESSES: BridgeContractAddresses = { + uniswapBridge: NULL_ADDRESS, + uniswapV2Bridge: NULL_ADDRESS, + eth2DaiBridge: NULL_ADDRESS, + kyberBridge: NULL_ADDRESS, + curveBridge: NULL_ADDRESS, + multiBridge: NULL_ADDRESS, + balancerBridge: NULL_ADDRESS, + bancorBridge: NULL_ADDRESS, + mStableBridge: NULL_ADDRESS, + mooniswapBridge: NULL_ADDRESS, + sushiswapBridge: NULL_ADDRESS, + shellBridge: NULL_ADDRESS, + dodoBridge: NULL_ADDRESS, + creamBridge: NULL_ADDRESS, + snowswapBridge: NULL_ADDRESS, + swerveBridge: NULL_ADDRESS, +}; + +export const BRIDGE_ADDRESSES_BY_CHAIN: { [chainId in ChainId]: BridgeContractAddresses } = { + [ChainId.Mainnet]: { + uniswapBridge: '0x36691c4f426eb8f42f150ebde43069a31cb080ad', + uniswapV2Bridge: '0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48', + kyberBridge: '0xadd97271402590564ddd8ad23cb5317b1fb0fffb', + eth2DaiBridge: '0x991c745401d5b5e469b8c3e2cb02c748f08754f1', + curveBridge: '0x1796cd592d19e3bcd744fbb025bb61a6d8cb2c09', + multiBridge: '0xc03117a8c9bde203f70aa911cb64a7a0df5ba1e1', + balancerBridge: '0xfe01821ca163844203220cd08e4f2b2fb43ae4e4', + bancorBridge: '0x259897d9699553edbdf8538599242354e957fb94', + mStableBridge: '0x2bf04fcea05f0989a14d9afa37aa376baca6b2b3', + mooniswapBridge: '0x02b7eca484ad960fca3f7709e0b2ac81eec3069c', + sushiswapBridge: '0x47ed0262a0b688dcb836d254c6a2e96b6c48a9f5', + shellBridge: '0x21fb3862eed7911e0f8219a077247b849846728d', + dodoBridge: '0xe9da66965a9344aab2167e6813c03f043cc7a6ca', + creamBridge: '0xb9d4bf2c8dab828f4ffb656acdb6c2b497d44f25', + swerveBridge: '0xf9786d5eb1de47fa56a8f7bb387653c6d410bfee', + snowswapBridge: '0xb1dbe83d15236ec10fdb214c6b89774b454754fd', + }, + [ChainId.Kovan]: { + ...EMPTY_BRIDGE_ADDRESSES, + uniswapBridge: '0x0e85f89f29998df65402391478e5924700c0079d', + uniswapV2Bridge: '0x7b3530a635d099de0534dc27e46cd7c57578c3c8', + eth2DaiBridge: '0x2d47147429b474d2e4f83e658015858a1312ed5b', + kyberBridge: '0xaecfa25920f892b6eb496e1f6e84037f59da7f44', + curveBridge: '0x81c0ab53a7352d2e97f682a37cba44e54647eefb', + balancerBridge: '0x407b4128e9ecad8769b2332312a9f655cb9f5f3a', + }, + [ChainId.Rinkeby]: EMPTY_BRIDGE_ADDRESSES, + [ChainId.Ropsten]: EMPTY_BRIDGE_ADDRESSES, + [ChainId.Ganache]: EMPTY_BRIDGE_ADDRESSES, +}; + +// tslint:disable:custom-no-magic-numbers +export const DEFAULT_GAS_SCHEDULE: FeeSchedule = { + [ERC20BridgeSource.Native]: () => 150e3, + [ERC20BridgeSource.Uniswap]: () => 90e3, + [ERC20BridgeSource.LiquidityProvider]: () => 140e3, + [ERC20BridgeSource.Eth2Dai]: () => 400e3, + [ERC20BridgeSource.Kyber]: () => 500e3, + [ERC20BridgeSource.Curve]: fillData => { + const poolAddress = (fillData as CurveFillData).pool.poolAddress.toLowerCase(); + switch (poolAddress) { + case '0xa5407eae9ba41422680e2e00537571bcc53efbfd': + case '0x93054188d876f558f4a66b2ef1d97d16edf0895b': + case '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714': + case '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7': + return 150e3; + case '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56': + return 750e3; + case '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51': + return 850e3; + case '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27': + return 1e6; + case '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c': + return 600e3; + default: + throw new Error(`Unrecognized Curve address: ${poolAddress}`); + } + }, + [ERC20BridgeSource.MultiBridge]: () => 350e3, + [ERC20BridgeSource.UniswapV2]: (fillData?: FillData) => { + // TODO: Different base cost if to/from ETH. + let gas = 90e3; + const path = (fillData as UniswapV2FillData).tokenAddressPath; + if (path.length > 2) { + gas += (path.length - 2) * 60e3; // +60k for each hop. + } + return gas; + }, + [ERC20BridgeSource.SushiSwap]: (fillData?: FillData) => { + // TODO: Different base cost if to/from ETH. + let gas = 95e3; + const path = (fillData as SushiSwapFillData).tokenAddressPath; + if (path.length > 2) { + gas += (path.length - 2) * 60e3; // +60k for each hop. + } + return gas; + }, + [ERC20BridgeSource.Balancer]: () => 120e3, + [ERC20BridgeSource.Cream]: () => 300e3, + [ERC20BridgeSource.MStable]: () => 700e3, + [ERC20BridgeSource.Mooniswap]: () => 220e3, + [ERC20BridgeSource.Swerve]: () => 150e3, + [ERC20BridgeSource.Shell]: () => 300e3, + [ERC20BridgeSource.MultiHop]: (fillData?: FillData) => { + const firstHop = (fillData as MultiHopFillData).firstHopSource; + const secondHop = (fillData as MultiHopFillData).secondHopSource; + const firstHopGas = DEFAULT_GAS_SCHEDULE[firstHop.source]!(firstHop.fillData); + const secondHopGas = DEFAULT_GAS_SCHEDULE[secondHop.source]!(secondHop.fillData); + return new BigNumber(firstHopGas) + .plus(secondHopGas) + .plus(30e3) + .toNumber(); + }, + [ERC20BridgeSource.Dodo]: (fillData?: FillData) => { + const isSellBase = (fillData as DODOFillData).isSellBase; + // Sell base is cheaper as it is natively supported + // sell quote requires additional calculation and overhead + return isSellBase ? 440e3 : 540e3; + }, +}; + +export const DEFAULT_FEE_SCHEDULE: FeeSchedule = Object.assign( + {}, + ...(Object.keys(DEFAULT_GAS_SCHEDULE) as ERC20BridgeSource[]).map(k => ({ + [k]: + k === ERC20BridgeSource.Native + ? (fillData: FillData) => PROTOCOL_FEE_MULTIPLIER.plus(DEFAULT_GAS_SCHEDULE[k]!(fillData)) + : (fillData: FillData) => DEFAULT_GAS_SCHEDULE[k]!(fillData), + })), +); + +// tslint:enable:custom-no-magic-numbers + +export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = { + // tslint:disable-next-line: custom-no-magic-numbers + runLimit: 2 ** 15, + excludedSources: [], + excludedFeeSources: [], + includedSources: [], + bridgeSlippage: 0.005, + maxFallbackSlippage: 0.05, + numSamples: 13, + sampleDistributionBase: 1.05, + feeSchedule: DEFAULT_FEE_SCHEDULE, + gasSchedule: DEFAULT_GAS_SCHEDULE, + exchangeProxyOverhead: () => ZERO_AMOUNT, + allowFallback: true, + shouldGenerateQuoteReport: false, +}; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/index.ts b/packages/asset-swapper/src/utils/market_operation_utils/index.ts index ff176d09dc..c2f75f6152 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -1,12 +1,11 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { Web3Wrapper } from '@0x/dev-utils'; import { RFQTIndicativeQuote } from '@0x/quote-server'; import { SignedOrder } from '@0x/types'; import { BigNumber, NULL_ADDRESS } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import { IS_PRICE_AWARE_RFQ_ENABLED } from '../../constants'; -import { MarketOperation, Omit } from '../../types'; +import { AssetSwapperContractAddresses, MarketOperation, Omit } from '../../types'; import { QuoteRequestor } from '../quote_requestor'; import { generateQuoteReport, QuoteReport } from './../quote_report_generator'; @@ -106,7 +105,7 @@ export class MarketOperationUtils { constructor( private readonly _sampler: DexOrderSampler, - private readonly contractAddresses: ContractAddresses, + private readonly contractAddresses: AssetSwapperContractAddresses, private readonly _orderDomain: OrderDomain, private readonly _liquidityProviderRegistry: string = NULL_ADDRESS, private readonly _tokenAdjacencyGraph: TokenAdjacencyGraph = {}, 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 29b1d6ba01..e083bd9fe9 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts @@ -1,10 +1,9 @@ -import { ContractAddresses } from '@0x/contract-addresses'; import { assetDataUtils, ERC20AssetData, generatePseudoRandomSalt, orderCalculationUtils } from '@0x/order-utils'; import { RFQTIndicativeQuote } from '@0x/quote-server'; import { SignedOrder } from '@0x/types'; import { AbiEncoder, BigNumber } from '@0x/utils'; -import { MarketOperation, SignedOrderWithFillableAmounts } from '../../types'; +import { AssetSwapperContractAddresses, MarketOperation, SignedOrderWithFillableAmounts } from '../../types'; import { ERC20_PROXY_ID, @@ -135,7 +134,7 @@ export interface CreateOrderFromPathOpts { inputToken: string; outputToken: string; orderDomain: OrderDomain; - contractAddresses: ContractAddresses; + contractAddresses: AssetSwapperContractAddresses; bridgeSlippage: number; } @@ -182,9 +181,9 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath case ERC20BridgeSource.Curve: return opts.contractAddresses.curveBridge; case ERC20BridgeSource.Swerve: - return opts.contractAddresses.curveBridge; + return opts.contractAddresses.swerveBridge; case ERC20BridgeSource.SnowSwap: - return opts.contractAddresses.curveBridge; + return opts.contractAddresses.snowswapBridge; case ERC20BridgeSource.Bancor: return opts.contractAddresses.bancorBridge; case ERC20BridgeSource.Balancer: 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 fe097c31a8..6067eabf6e 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 @@ -1,6 +1,6 @@ import { SupportedProvider } from '@0x/dev-utils'; import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, NULL_ADDRESS } from '@0x/utils'; import * as _ from 'lodash'; import { ERC20BridgeSamplerContract } from '../../wrappers'; @@ -1054,7 +1054,7 @@ export class SamplerOperations { const _sources = BATCH_SOURCE_FILTERS.exclude( liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider], ) - .exclude(multiBridgeAddress ? [] : [ERC20BridgeSource.MultiBridge]) + .exclude(multiBridgeAddress || multiBridgeAddress === NULL_ADDRESS ? [] : [ERC20BridgeSource.MultiBridge]) .getAllowed(sources); return _.flatten( _sources.map( diff --git a/packages/asset-swapper/test/artifacts.ts b/packages/asset-swapper/test/artifacts.ts index 6208f93c41..02f8ed1ff6 100644 --- a/packages/asset-swapper/test/artifacts.ts +++ b/packages/asset-swapper/test/artifacts.ts @@ -8,6 +8,7 @@ import { ContractArtifact } from 'ethereum-types'; import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json'; import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json'; import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json'; +import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json'; import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json'; import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json'; import * as DummyLiquidityProviderRegistry from '../test/generated-artifacts/DummyLiquidityProviderRegistry.json'; @@ -44,9 +45,9 @@ export const artifacts = { BalancerSampler: BalancerSampler as ContractArtifact, CurveSampler: CurveSampler as ContractArtifact, DODOSampler: DODOSampler as ContractArtifact, + DeploymentConstants: DeploymentConstants as ContractArtifact, ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact, Eth2DaiSampler: Eth2DaiSampler as ContractArtifact, - IMooniswap: IMooniswap as ContractArtifact, KyberSampler: KyberSampler as ContractArtifact, LiquidityProviderSampler: LiquidityProviderSampler as ContractArtifact, MStableSampler: MStableSampler as ContractArtifact, @@ -66,6 +67,7 @@ export const artifacts = { ILiquidityProvider: ILiquidityProvider as ContractArtifact, ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact, IMStable: IMStable as ContractArtifact, + IMooniswap: IMooniswap as ContractArtifact, IMultiBridge: IMultiBridge as ContractArtifact, IShell: IShell as ContractArtifact, IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact, diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index 3ec9351e91..4c2ba7e68d 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -1,5 +1,5 @@ // tslint:disable: no-unbound-method -import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; +import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; import { assertRoughlyEquals, constants, @@ -9,10 +9,10 @@ import { Numberish, randomAddress, } from '@0x/contracts-test-utils'; -import { Web3Wrapper } from '@0x/dev-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; import { AssetProxyId, ERC20BridgeAssetData, SignedOrder } from '@0x/types'; import { BigNumber, fromTokenUnitAmount, hexUtils, NULL_ADDRESS } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import * as TypeMoq from 'typemoq'; @@ -21,6 +21,7 @@ import { IS_PRICE_AWARE_RFQ_ENABLED } from '../src/constants'; import { getRfqtIndicativeQuotesAsync, MarketOperationUtils } from '../src/utils/market_operation_utils/'; import { BalancerPoolsCache } from '../src/utils/market_operation_utils/balancer_utils'; import { + BRIDGE_ADDRESSES_BY_CHAIN, BUY_SOURCE_FILTER, POSITIVE_INF, SELL_SOURCE_FILTER, @@ -38,6 +39,7 @@ import { ERC20BridgeSource, FillData, GenerateOptimizedOrdersOpts, + GetMarketOrdersOpts, MarketSideLiquidity, NativeFillData, } from '../src/utils/market_operation_utils/types'; @@ -66,8 +68,12 @@ const SELL_SOURCES = SELL_SOURCE_FILTER.sources; // tslint:disable: custom-no-magic-numbers promise-function-async describe('MarketOperationUtils tests', () => { - const CHAIN_ID = 1; - const contractAddresses = { ...getContractAddressesForChainOrThrow(CHAIN_ID), multiBridge: NULL_ADDRESS }; + const CHAIN_ID = ChainId.Mainnet; + const contractAddresses = { + ...getContractAddressesForChainOrThrow(CHAIN_ID), + multiBridge: NULL_ADDRESS, + ...BRIDGE_ADDRESSES_BY_CHAIN[CHAIN_ID], + }; function getMockedQuoteRequestor( type: 'indicative' | 'firm', @@ -522,13 +528,15 @@ describe('MarketOperationUtils tests', () => { FILL_AMOUNT, _.times(NUM_SAMPLES, i => DEFAULT_RATES[ERC20BridgeSource.Native][i]), ); - const DEFAULT_OPTS = { + const DEFAULT_OPTS: Partial = { numSamples: NUM_SAMPLES, sampleDistributionBase: 1, bridgeSlippage: 0, maxFallbackSlippage: 100, excludedSources: DEFAULT_EXCLUDED, allowFallback: false, + gasSchedule: {}, + feeSchedule: {}, }; beforeEach(() => { @@ -1428,7 +1436,7 @@ describe('MarketOperationUtils tests', () => { ...DEFAULT_OPTS, numSamples: 4, excludedSources: [ - ...DEFAULT_OPTS.excludedSources, + ...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]), ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Kyber, ERC20BridgeSource.Bancor, @@ -1449,13 +1457,15 @@ describe('MarketOperationUtils tests', () => { FILL_AMOUNT, _.times(NUM_SAMPLES, () => DEFAULT_RATES[ERC20BridgeSource.Native][0]), ); - const DEFAULT_OPTS = { + const DEFAULT_OPTS: Partial = { numSamples: NUM_SAMPLES, sampleDistributionBase: 1, bridgeSlippage: 0, maxFallbackSlippage: 100, excludedSources: DEFAULT_EXCLUDED, allowFallback: false, + gasSchedule: {}, + feeSchedule: {}, }; beforeEach(() => { @@ -1869,7 +1879,7 @@ describe('MarketOperationUtils tests', () => { ...DEFAULT_OPTS, numSamples: 4, excludedSources: [ - ...DEFAULT_OPTS.excludedSources, + ...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]), ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Kyber, ], diff --git a/packages/asset-swapper/test/utils/mock_sampler_contract.ts b/packages/asset-swapper/test/utils/mock_sampler_contract.ts index 558f17a123..eb261f0b05 100644 --- a/packages/asset-swapper/test/utils/mock_sampler_contract.ts +++ b/packages/asset-swapper/test/utils/mock_sampler_contract.ts @@ -1,4 +1,4 @@ -import { ContractFunctionObj } from '@0x/base-contract'; +import { ContractTxFunctionObj } from '@0x/base-contract'; import { constants } from '@0x/contracts-test-utils'; import { Order } from '@0x/types'; import { BigNumber, hexUtils } from '@0x/utils'; @@ -82,7 +82,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { this._handlers = handlers; } - public batchCall(callDatas: string[]): ContractFunctionObj { + public batchCall(callDatas: string[]): ContractTxFunctionObj { return { ...super.batchCall(callDatas), callAsync: async (..._callArgs: any[]) => callDatas.map(callData => this._callEncodedFunction(callData)), @@ -92,7 +92,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { public getOrderFillableMakerAssetAmounts( orders: Order[], signatures: string[], - ): ContractFunctionObj { + ): ContractTxFunctionObj { return this._wrapCall( super.getOrderFillableMakerAssetAmounts, this._handlers.getOrderFillableMakerAssetAmounts, @@ -105,7 +105,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { public getOrderFillableTakerAssetAmounts( orders: Order[], signatures: string[], - ): ContractFunctionObj { + ): ContractTxFunctionObj { return this._wrapCall( super.getOrderFillableTakerAssetAmounts, this._handlers.getOrderFillableTakerAssetAmounts, @@ -120,7 +120,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { takerToken: string, makerToken: string, takerAssetAmounts: BigNumber[], - ): ContractFunctionObj<[string, BigNumber[]]> { + ): ContractTxFunctionObj<[string, BigNumber[]]> { return this._wrapCall( super.sampleSellsFromKyberNetwork, this._handlers.sampleSellsFromKyberNetwork, @@ -135,7 +135,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { takerToken: string, makerToken: string, takerAssetAmounts: BigNumber[], - ): ContractFunctionObj { + ): ContractTxFunctionObj { return this._wrapCall( super.sampleSellsFromEth2Dai, this._handlers.sampleSellsFromEth2Dai, @@ -149,7 +149,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { takerToken: string, makerToken: string, takerAssetAmounts: BigNumber[], - ): ContractFunctionObj { + ): ContractTxFunctionObj { return this._wrapCall( super.sampleSellsFromUniswap, this._handlers.sampleSellsFromUniswap, @@ -159,7 +159,10 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { ); } - public sampleSellsFromUniswapV2(path: string[], takerAssetAmounts: BigNumber[]): ContractFunctionObj { + public sampleSellsFromUniswapV2( + path: string[], + takerAssetAmounts: BigNumber[], + ): ContractTxFunctionObj { return this._wrapCall( super.sampleSellsFromUniswapV2, this._handlers.sampleSellsFromUniswapV2, @@ -173,7 +176,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { takerToken: string, makerToken: string, takerAssetAmounts: BigNumber[], - ): ContractFunctionObj<[BigNumber[], string]> { + ): ContractTxFunctionObj<[BigNumber[], string]> { return this._wrapCall( super.sampleSellsFromLiquidityProviderRegistry, this._handlers.sampleSellsFromLiquidityProviderRegistry, @@ -190,7 +193,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { intermediateToken: string, makerToken: string, takerAssetAmounts: BigNumber[], - ): ContractFunctionObj { + ): ContractTxFunctionObj { return this._wrapCall( super.sampleSellsFromMultiBridge, this._handlers.sampleSellsFromMultiBridge, @@ -206,7 +209,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { takerToken: string, makerToken: string, makerAssetAmounts: BigNumber[], - ): ContractFunctionObj { + ): ContractTxFunctionObj { return this._wrapCall( super.sampleBuysFromEth2Dai, this._handlers.sampleBuysFromEth2Dai, @@ -220,7 +223,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { takerToken: string, makerToken: string, makerAssetAmounts: BigNumber[], - ): ContractFunctionObj { + ): ContractTxFunctionObj { return this._wrapCall( super.sampleBuysFromUniswap, this._handlers.sampleBuysFromUniswap, @@ -230,7 +233,7 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { ); } - public sampleBuysFromUniswapV2(path: string[], makerAssetAmounts: BigNumber[]): ContractFunctionObj { + public sampleBuysFromUniswapV2(path: string[], makerAssetAmounts: BigNumber[]): ContractTxFunctionObj { return this._wrapCall( super.sampleBuysFromUniswapV2, this._handlers.sampleBuysFromUniswapV2, @@ -266,11 +269,11 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { } private _wrapCall( - superFn: (this: MockSamplerContract, ...args: TArgs) => ContractFunctionObj, + superFn: (this: MockSamplerContract, ...args: TArgs) => ContractTxFunctionObj, handler?: (this: MockSamplerContract, ...args: TArgs) => TResult, // tslint:disable-next-line: trailing-comma ...args: TArgs - ): ContractFunctionObj { + ): ContractTxFunctionObj { return { ...superFn.call(this, ...args), callAsync: async (..._callArgs: any[]): Promise => { diff --git a/packages/asset-swapper/test/wrappers.ts b/packages/asset-swapper/test/wrappers.ts index 5a57f5a88d..69c32cad67 100644 --- a/packages/asset-swapper/test/wrappers.ts +++ b/packages/asset-swapper/test/wrappers.ts @@ -7,6 +7,7 @@ export * from '../test/generated-wrappers/approximate_buys'; export * from '../test/generated-wrappers/balancer_sampler'; export * from '../test/generated-wrappers/curve_sampler'; export * from '../test/generated-wrappers/d_o_d_o_sampler'; +export * from '../test/generated-wrappers/deployment_constants'; export * from '../test/generated-wrappers/dummy_liquidity_provider'; export * from '../test/generated-wrappers/dummy_liquidity_provider_registry'; export * from '../test/generated-wrappers/erc20_bridge_sampler'; diff --git a/packages/asset-swapper/tsconfig.json b/packages/asset-swapper/tsconfig.json index e51b0a53da..d56c814b13 100644 --- a/packages/asset-swapper/tsconfig.json +++ b/packages/asset-swapper/tsconfig.json @@ -12,6 +12,7 @@ "test/generated-artifacts/BalancerSampler.json", "test/generated-artifacts/CurveSampler.json", "test/generated-artifacts/DODOSampler.json", + "test/generated-artifacts/DeploymentConstants.json", "test/generated-artifacts/DummyLiquidityProvider.json", "test/generated-artifacts/DummyLiquidityProviderRegistry.json", "test/generated-artifacts/ERC20BridgeSampler.json", diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index 7066962e4b..63cb3fb672 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "5.0.0", + "changes": [ + { + "note": "Moved Bridge addresses into Asset-swapper", + "pr": 4 + } + ] + }, { "version": "4.12.0", "changes": [ diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index 80aad5c1c8..c903140e23 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -19,33 +19,19 @@ "stakingProxy": "0xa26e80e7dea86279c6d778d702cc413e6cffa777", "devUtils": "0x74134cf88b21383713e096a5ecf59e297dc7f547", "erc20BridgeProxy": "0x8ed95d1746bf1e4dab58d8ed4724f1ef95b20db0", - "uniswapBridge": "0x36691c4f426eb8f42f150ebde43069a31cb080ad", - "uniswapV2Bridge": "0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48", "erc20BridgeSampler": "0xd8c38704c9937ea3312de29f824b4ad3450a5e61", - "kyberBridge": "0xadd97271402590564ddd8ad23cb5317b1fb0fffb", - "eth2DaiBridge": "0x991c745401d5b5e469b8c3e2cb02c748f08754f1", "chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438", "dydxBridge": "0x92af95e37afddac412e5688a9dcc1dd815d4ae53", "godsUnchainedValidator": "0x09a379ef7218bcfd8913faa8b281ebc5a2e0bc04", "broker": "0xd4690a51044db77d91d7aa8f7a3a5ad5da331af0", "chainlinkStopLimit": "0xeb27220f95f364e1d9531992c48613f231839f53", - "curveBridge": "0x1796cd592d19e3bcd744fbb025bb61a6d8cb2c09", "maximumGasPrice": "0xe2bfd35306495d11e3c9db0d8de390cda24563cf", "dexForwarderBridge": "0xc47b7094f378e54347e281aab170e8cca69d880a", - "multiBridge": "0xc03117a8c9bde203f70aa911cb64a7a0df5ba1e1", - "balancerBridge": "0xfe01821ca163844203220cd08e4f2b2fb43ae4e4", - "bancorBridge": "0x259897d9699553edbdf8538599242354e957fb94", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x39dce47a67ad34344eab877eae3ef1fa2a1d50bb", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", - "mStableBridge": "0x2bf04fcea05f0989a14d9afa37aa376baca6b2b3", - "mooniswapBridge": "0x02b7eca484ad960fca3f7709e0b2ac81eec3069c", - "sushiswapBridge": "0x47ed0262a0b688dcb836d254c6a2e96b6c48a9f5", - "shellBridge": "0x21fb3862eed7911e0f8219a077247b849846728d", - "dodoBridge": "0xe9da66965a9344aab2167e6813c03f043cc7a6ca", - "creamBridge": "0xb9d4bf2c8dab828f4ffb656acdb6c2b497d44f25", "transformers": { "wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e", "payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7", @@ -73,33 +59,19 @@ "staking": "0x4af649ffde640ceb34b1afaba3e0bb8e9698cb01", "stakingProxy": "0x6acab4c9c4e3a0c78435fdb5ad1719c95460a668", "erc20BridgeProxy": "0xb344afed348de15eb4a9e180205a2b0739628339", - "uniswapBridge": "0x0000000000000000000000000000000000000000", - "uniswapV2Bridge": "0x0000000000000000000000000000000000000000", - "eth2DaiBridge": "0x0000000000000000000000000000000000000000", "erc20BridgeSampler": "0x0000000000000000000000000000000000000000", - "kyberBridge": "0x0000000000000000000000000000000000000000", "chaiBridge": "0x0000000000000000000000000000000000000000", "dydxBridge": "0x0000000000000000000000000000000000000000", "godsUnchainedValidator": "0xd4690a51044db77d91d7aa8f7a3a5ad5da331af0", "broker": "0x4022e3982f326455f0905de3dbc4449999baf2dc", "chainlinkStopLimit": "0x67a094cf028221ffdd93fc658f963151d05e2a74", - "curveBridge": "0x1796cd592d19e3bcd744fbb025bb61a6d8cb2c09", "maximumGasPrice": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a", "dexForwarderBridge": "0x3261ea1411a1a840aed708896f779e1b837c917e", - "multiBridge": "0x0000000000000000000000000000000000000000", - "balancerBridge": "0x47697b44bd89051e93b4d5857ba8e024800a74ac", - "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", - "mStableBridge": "0x0000000000000000000000000000000000000000", - "mooniswapBridge": "0x0000000000000000000000000000000000000000", - "sushiswapBridge": "0x0000000000000000000000000000000000000000", - "shellBridge": "0x0000000000000000000000000000000000000000", - "dodoBridge": "0x0000000000000000000000000000000000000000", - "creamBridge": "0x0000000000000000000000000000000000000000", "transformers": { "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", @@ -127,33 +99,19 @@ "staking": "0x6acab4c9c4e3a0c78435fdb5ad1719c95460a668", "stakingProxy": "0x781ee6683595f823208be6540a279f940e6af196", "erc20BridgeProxy": "0xa2aa4befed748fba27a3be7dfd2c4b2c6db1f49b", - "uniswapBridge": "0x0000000000000000000000000000000000000000", - "uniswapV2Bridge": "0x0000000000000000000000000000000000000000", - "eth2DaiBridge": "0x0000000000000000000000000000000000000000", "erc20BridgeSampler": "0x0000000000000000000000000000000000000000", - "kyberBridge": "0x0000000000000000000000000000000000000000", "chaiBridge": "0x0000000000000000000000000000000000000000", "dydxBridge": "0x0000000000000000000000000000000000000000", "godsUnchainedValidator": "0x0000000000000000000000000000000000000000", "broker": "0x0dd2d6cabbd8ae7d2fe6840fa597a44b1a7e4747", "chainlinkStopLimit": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a", - "curveBridge": "0x1796cd592d19e3bcd744fbb025bb61a6d8cb2c09", "maximumGasPrice": "0x47697b44bd89051e93b4d5857ba8e024800a74ac", "dexForwarderBridge": "0x0000000000000000000000000000000000000000", - "multiBridge": "0x0000000000000000000000000000000000000000", - "balancerBridge": "0x5d8c9ba74607d2cbc4176882a42d4ace891c1c00", - "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", - "mStableBridge": "0x0000000000000000000000000000000000000000", - "mooniswapBridge": "0x0000000000000000000000000000000000000000", - "sushiswapBridge": "0x0000000000000000000000000000000000000000", - "shellBridge": "0x0000000000000000000000000000000000000000", - "dodoBridge": "0x0000000000000000000000000000000000000000", - "creamBridge": "0x0000000000000000000000000000000000000000", "transformers": { "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", @@ -181,33 +139,19 @@ "staking": "0x73ea24041e03a012c51a45c307e0ba376af0238c", "stakingProxy": "0xe94cb304b3f515be7c95fedcfa249a84995fd748", "erc20BridgeProxy": "0x3577552c1fb7a44ad76beeb7ab53251668a21f8d", - "uniswapBridge": "0x0e85f89f29998df65402391478e5924700c0079d", - "uniswapV2Bridge": "0x7b3530a635d099de0534dc27e46cd7c57578c3c8", - "eth2DaiBridge": "0x2d47147429b474d2e4f83e658015858a1312ed5b", "erc20BridgeSampler": "0xcf9e66851f274aa4721e54526117876d90d51aa1", - "kyberBridge": "0xaecfa25920f892b6eb496e1f6e84037f59da7f44", "chaiBridge": "0x0000000000000000000000000000000000000000", "dydxBridge": "0xc213707de0454008758071c2edc1365621b8a5c5", "godsUnchainedValidator": "0x0000000000000000000000000000000000000000", "broker": "0xcdeb6d90ee7c96b4c713f7bb4f8604981f7ebe9d", "chainlinkStopLimit": "0x0000000000000000000000000000000000000000", - "curveBridge": "0x81c0ab53a7352d2e97f682a37cba44e54647eefb", "maximumGasPrice": "0x67a094cf028221ffdd93fc658f963151d05e2a74", "dexForwarderBridge": "0x985d1a95c6a86a3bf85c4d425af984abceaf01de", - "multiBridge": "0x0000000000000000000000000000000000000000", - "balancerBridge": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a", - "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x1b62de2dbb5e7aa519e9c442721ecef75702807f", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", - "mStableBridge": "0x0000000000000000000000000000000000000000", - "mooniswapBridge": "0x0000000000000000000000000000000000000000", - "sushiswapBridge": "0x0000000000000000000000000000000000000000", - "shellBridge": "0x0000000000000000000000000000000000000000", - "dodoBridge": "0x0000000000000000000000000000000000000000", - "creamBridge": "0x0000000000000000000000000000000000000000", "transformers": { "wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d", "payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977", @@ -235,33 +179,19 @@ "zrxVault": "0xf23276778860e420acfc18ebeebf7e829b06965c", "staking": "0x8a063452f7df2614db1bca3a85ef35da40cf0835", "stakingProxy": "0x59adefa01843c627ba5d6aa350292b4b7ccae67a", - "uniswapBridge": "0x0000000000000000000000000000000000000000", - "uniswapV2Bridge": "0x0000000000000000000000000000000000000000", - "eth2DaiBridge": "0x0000000000000000000000000000000000000000", "erc20BridgeSampler": "0x0000000000000000000000000000000000000000", - "kyberBridge": "0x0000000000000000000000000000000000000000", "chaiBridge": "0x0000000000000000000000000000000000000000", "dydxBridge": "0x0000000000000000000000000000000000000000", "godsUnchainedValidator": "0x0000000000000000000000000000000000000000", "broker": "0x0000000000000000000000000000000000000000", "chainlinkStopLimit": "0x0000000000000000000000000000000000000000", - "curveBridge": "0x0000000000000000000000000000000000000000", "maximumGasPrice": "0x0000000000000000000000000000000000000000", "dexForwarderBridge": "0x0000000000000000000000000000000000000000", - "multiBridge": "0x0000000000000000000000000000000000000000", - "balancerBridge": "0x0000000000000000000000000000000000000000", - "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x0000000000000000000000000000000000000000", "exchangeProxy": "0x5315e44798395d4a952530d131249fe00f554565", "exchangeProxyAllowanceTarget": "0x8362c3ebd90041b30ec45908332e592721642637", "exchangeProxyTransformerDeployer": "0x5409ed021d9299bf6814279a6a1411a7e866a631", "exchangeProxyFlashWallet": "0xb9682a8e7920b431f1d412b8510f0077410c8faa", - "mStableBridge": "0x0000000000000000000000000000000000000000", - "mooniswapBridge": "0x0000000000000000000000000000000000000000", - "sushiswapBridge": "0x0000000000000000000000000000000000000000", - "shellBridge": "0x0000000000000000000000000000000000000000", - "dodoBridge": "0x0000000000000000000000000000000000000000", - "creamBridge": "0x0000000000000000000000000000000000000000", "transformers": { "wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5", "payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3", diff --git a/packages/contract-addresses/src/index.ts b/packages/contract-addresses/src/index.ts index a2f7c6be04..d140ef8c44 100644 --- a/packages/contract-addresses/src/index.ts +++ b/packages/contract-addresses/src/index.ts @@ -21,32 +21,18 @@ export interface ContractAddresses { stakingProxy: string; erc20BridgeProxy: string; erc20BridgeSampler: string; - uniswapBridge: string; - uniswapV2Bridge: string; - eth2DaiBridge: string; - kyberBridge: string; chaiBridge: string; dydxBridge: string; - curveBridge: string; godsUnchainedValidator: string; broker: string; chainlinkStopLimit: string; maximumGasPrice: string; dexForwarderBridge: string; - multiBridge: string; - balancerBridge: string; - bancorBridge: string; exchangeProxyGovernor: string; exchangeProxy: string; exchangeProxyAllowanceTarget: string; exchangeProxyTransformerDeployer: string; exchangeProxyFlashWallet: string; - mStableBridge: string; - mooniswapBridge: string; - sushiswapBridge: string; - shellBridge: string; - dodoBridge: string; - creamBridge: string; transformers: { wethTransformer: string; payTakerTransformer: string; diff --git a/packages/migrations/src/migration.ts b/packages/migrations/src/migration.ts index 542eb7786f..e0a6d1785c 100644 --- a/packages/migrations/src/migration.ts +++ b/packages/migrations/src/migration.ts @@ -317,16 +317,22 @@ export async function runMigrationsAsync( mooniswapBridge: NULL_ADDRESS, mStableBridge: NULL_ADDRESS, oasisBridge: NULL_ADDRESS, + swerveBridge: NULL_ADDRESS, + sushiswapBridge: NULL_ADDRESS, uniswapBridge: NULL_ADDRESS, uniswapV2Bridge: NULL_ADDRESS, kyberNetworkProxy: NULL_ADDRESS, oasis: NULL_ADDRESS, + sushiswapRouter: NULL_ADDRESS, uniswapV2Router: NULL_ADDRESS, uniswapExchangeFactory: NULL_ADDRESS, mStable: NULL_ADDRESS, shellBridge: NULL_ADDRESS, creamBridge: NULL_ADDRESS, shell: NULL_ADDRESS, + dodoBridge: NULL_ADDRESS, + dodoHelper: NULL_ADDRESS, + snowSwapBridge: NULL_ADDRESS, weth: etherToken.address, }, ); @@ -384,29 +390,15 @@ export async function runMigrationsAsync( zrxVault: zrxVault.address, staking: stakingLogic.address, stakingProxy: stakingProxy.address, - uniswapBridge: NULL_ADDRESS, - eth2DaiBridge: NULL_ADDRESS, - kyberBridge: NULL_ADDRESS, erc20BridgeSampler: NULL_ADDRESS, chaiBridge: NULL_ADDRESS, dydxBridge: NULL_ADDRESS, - curveBridge: NULL_ADDRESS, - uniswapV2Bridge: NULL_ADDRESS, godsUnchainedValidator: NULL_ADDRESS, broker: NULL_ADDRESS, chainlinkStopLimit: NULL_ADDRESS, maximumGasPrice: NULL_ADDRESS, dexForwarderBridge: NULL_ADDRESS, - multiBridge: NULL_ADDRESS, - balancerBridge: NULL_ADDRESS, - bancorBridge: NULL_ADDRESS, exchangeProxyGovernor: NULL_ADDRESS, - mStableBridge: NULL_ADDRESS, - mooniswapBridge: NULL_ADDRESS, - sushiswapBridge: NULL_ADDRESS, - shellBridge: NULL_ADDRESS, - dodoBridge: NULL_ADDRESS, - creamBridge: NULL_ADDRESS, exchangeProxy: exchangeProxy.address, exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress, exchangeProxyTransformerDeployer: txDefaults.from,