From 7403c0255a4ef9cff00f5781239637105b53e5f0 Mon Sep 17 00:00:00 2001 From: mzhu25 Date: Fri, 13 Nov 2020 12:22:21 -0800 Subject: [PATCH] Feature/liquidity provider sandbox (#16) * Update liquidity provider feature to use sandbox * add support for liquidity provider feature in the exchange proxy swap quote consumer * Move to off-chain liquidity provider registry * Update ILiquidityProvider interface * Remove some unused artifacts and wrappers * Consolidate ILiquidityProvider * prettier * lint * Address PR feedback * Add failover to sandbox * Add test for failover behavior in LiquidityProviderSandbox * Update changelogs * Emit events for the new LiquidityProvider scenarios * Fix swap quote consumer bug * post-rebase fixes * `@0x/contracts-zero-ex`: bump feature versions * Add default field to TokenAdjacencyGraph * update addresses Co-authored-by: Lawrence Forman --- contracts/zero-ex/CHANGELOG.json | 12 + .../errors/LibLiquidityProviderRichErrors.sol | 15 - .../external/ILiquidityProviderSandbox.sol | 74 ++++ .../src/external/LiquidityProviderSandbox.sol | 139 ++++++++ .../features/ILiquidityProviderFeature.sol | 53 +-- .../src/features/LiquidityProviderFeature.sol | 180 +++++----- .../src/features/TransformERC20Feature.sol | 2 +- .../contracts/src/features/UniswapFeature.sol | 2 +- .../storage/LibLiquidityProviderStorage.sol | 45 --- .../contracts/src/storage/LibStorage.sol | 3 +- .../zero-ex/contracts/test/TestBridge.sol | 6 +- .../test/TestFillQuoteTransformerBridge.sol | 34 +- .../contracts/test/TestLiquidityProvider.sol | 135 ++++++++ contracts/zero-ex/package.json | 4 +- contracts/zero-ex/src/artifacts.ts | 2 + contracts/zero-ex/src/wrappers.ts | 1 + contracts/zero-ex/test/artifacts.ts | 8 +- .../test/features/liquidity_provider_test.ts | 205 ++++++----- contracts/zero-ex/test/wrappers.ts | 4 +- contracts/zero-ex/tsconfig.json | 5 +- packages/asset-swapper/CHANGELOG.json | 13 + .../src/LiquidityProviderSampler.sol | 81 +---- .../src/interfaces/ILiquidityProvider.sol | 70 ---- .../interfaces/ILiquidityProviderRegistry.sol | 36 -- .../test/DummyLiquidityProviderRegistry.sol | 44 --- packages/asset-swapper/package.json | 5 +- packages/asset-swapper/src/artifacts.ts | 12 +- packages/asset-swapper/src/index.ts | 2 +- .../exchange_proxy_swap_quote_consumer.ts | 48 ++- .../src/quote_consumers/utils.ts | 2 +- packages/asset-swapper/src/swap_quoter.ts | 15 +- packages/asset-swapper/src/types.ts | 11 +- .../utils/market_operation_utils/constants.ts | 91 +++-- .../src/utils/market_operation_utils/index.ts | 70 +--- .../liquidity_provider_utils.ts | 12 + .../multibridge_utils.ts | 13 - .../market_operation_utils/multihop_utils.ts | 16 +- .../utils/market_operation_utils/orders.ts | 20 -- .../src/utils/market_operation_utils/path.ts | 12 +- .../utils/market_operation_utils/sampler.ts | 14 +- .../sampler_operations.ts | 259 +++----------- .../src/utils/market_operation_utils/types.ts | 9 +- packages/asset-swapper/src/wrappers.ts | 4 - packages/asset-swapper/test/artifacts.ts | 6 - .../contracts/erc20_bridge_sampler_test.ts | 49 +-- .../asset-swapper/test/dex_sampler_test.ts | 119 +++---- ...exchange_proxy_swap_quote_consumer_test.ts | 72 +++- .../test/market_operation_utils_test.ts | 212 ++---------- .../test/utils/mock_sampler_contract.ts | 44 +-- packages/asset-swapper/test/wrappers.ts | 3 - packages/asset-swapper/tsconfig.json | 7 - packages/contract-addresses/CHANGELOG.json | 9 + packages/contract-addresses/addresses.json | 5 + packages/contract-addresses/src/index.ts | 1 + packages/contract-artifacts/CHANGELOG.json | 9 + .../artifacts/DummyLiquidityProvider.json | 81 ----- .../DummyLiquidityProviderRegistry.json | 83 ----- .../artifacts/ILiquidityProviderRegistry.json | 58 ---- .../contract-artifacts/artifacts/IZeroEx.json | 66 +--- packages/contract-artifacts/package.json | 2 +- packages/contract-wrappers/CHANGELOG.json | 9 + .../i_liquidity_provider_registry.ts | 327 ------------------ .../src/generated-wrappers/i_zero_ex.ts | 220 ++---------- packages/contract-wrappers/src/index.ts | 1 - packages/migrations/CHANGELOG.json | 9 + packages/migrations/src/migration.ts | 1 + 66 files changed, 1083 insertions(+), 2098 deletions(-) create mode 100644 contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol create mode 100644 contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol delete mode 100644 contracts/zero-ex/contracts/src/storage/LibLiquidityProviderStorage.sol create mode 100644 contracts/zero-ex/contracts/test/TestLiquidityProvider.sol delete mode 100644 packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol delete mode 100644 packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol delete mode 100644 packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol create mode 100644 packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts delete mode 100644 packages/asset-swapper/src/utils/market_operation_utils/multibridge_utils.ts delete mode 100644 packages/contract-artifacts/artifacts/DummyLiquidityProvider.json delete mode 100644 packages/contract-artifacts/artifacts/DummyLiquidityProviderRegistry.json delete mode 100644 packages/contract-artifacts/artifacts/ILiquidityProviderRegistry.json delete mode 100644 packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider_registry.ts diff --git a/contracts/zero-ex/CHANGELOG.json b/contracts/zero-ex/CHANGELOG.json index a348d2bf44..fa0ab7437a 100644 --- a/contracts/zero-ex/CHANGELOG.json +++ b/contracts/zero-ex/CHANGELOG.json @@ -5,6 +5,18 @@ { "note": "Rewrite the ZeroEx contract in Yul", "pr": 23 + }, + { + "note": "Update LiquidityProviderFeature to use off-chain registry and sandbox", + "pr": 16 + }, + { + "note": "Update ILiquidityProvider interface", + "pr": 16 + }, + { + "note": "Update ProtocolFeeUnfunded event to emit order hash", + "pr": 16 } ] }, diff --git a/contracts/zero-ex/contracts/src/errors/LibLiquidityProviderRichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibLiquidityProviderRichErrors.sol index 177df23a08..045c3e698a 100644 --- a/contracts/zero-ex/contracts/src/errors/LibLiquidityProviderRichErrors.sol +++ b/contracts/zero-ex/contracts/src/errors/LibLiquidityProviderRichErrors.sol @@ -45,19 +45,4 @@ library LibLiquidityProviderRichErrors { minBuyAmount ); } - - function NoLiquidityProviderForMarketError( - address xAsset, - address yAsset - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("NoLiquidityProviderForMarketError(address,address)")), - xAsset, - yAsset - ); - } } diff --git a/contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol b/contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol new file mode 100644 index 0000000000..e0a4d5981f --- /dev/null +++ b/contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol @@ -0,0 +1,74 @@ +/* + + 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; + + +interface ILiquidityProviderSandbox { + + /// @dev Calls `sellTokenForToken` on the given `provider` contract to + /// trigger a trade. + /// @param provider The address of the on-chain liquidity provider. + /// @param inputToken The token being sold. + /// @param outputToken The token being bought. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + function executeSellTokenForToken( + address provider, + address inputToken, + address outputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external; + + /// @dev Calls `sellEthForToken` on the given `provider` contract to + /// trigger a trade. + /// @param provider The address of the on-chain liquidity provider. + /// @param outputToken The token being bought. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + function executeSellEthForToken( + address provider, + address outputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external; + + /// @dev Calls `sellTokenForEth` on the given `provider` contract to + /// trigger a trade. + /// @param provider The address of the on-chain liquidity provider. + /// @param inputToken The token being sold. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of ETH to buy. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + function executeSellTokenForEth( + address provider, + address inputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external; +} diff --git a/contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol b/contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol new file mode 100644 index 0000000000..30fea8ec71 --- /dev/null +++ b/contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol @@ -0,0 +1,139 @@ +/* + 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-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; +import "@0x/contracts-utils/contracts/src/v06/errors/LibOwnableRichErrorsV06.sol"; +import "../vendor/ILiquidityProvider.sol"; +import "../vendor/v3/IERC20Bridge.sol"; +import "./ILiquidityProviderSandbox.sol"; + + +/// @dev A permissionless contract through which the ZeroEx contract can +/// safely trigger a trade on an external `ILiquidityProvider` contract. +contract LiquidityProviderSandbox is + ILiquidityProviderSandbox +{ + using LibRichErrorsV06 for bytes; + + /// @dev Store the owner as an immutable. + address public immutable owner; + + constructor(address owner_) + public + { + owner = owner_; + } + + /// @dev Allows only the (immutable) owner to call a function. + modifier onlyOwner() virtual { + if (msg.sender != owner) { + LibOwnableRichErrorsV06.OnlyOwnerError( + msg.sender, + owner + ).rrevert(); + } + _; + } + + /// @dev Calls `sellTokenForToken` on the given `provider` contract to + /// trigger a trade. + /// @param provider The address of the on-chain liquidity provider. + /// @param inputToken The token being sold. + /// @param outputToken The token being bought. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + function executeSellTokenForToken( + address provider, + address inputToken, + address outputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external + onlyOwner + override + { + try ILiquidityProvider(provider).sellTokenForToken( + inputToken, + outputToken, + recipient, + minBuyAmount, + auxiliaryData + ) {} catch { + IERC20Bridge(provider).bridgeTransferFrom( + outputToken, + provider, + recipient, + minBuyAmount, + auxiliaryData + ); + } + } + + /// @dev Calls `sellEthForToken` on the given `provider` contract to + /// trigger a trade. + /// @param provider The address of the on-chain liquidity provider. + /// @param outputToken The token being bought. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + function executeSellEthForToken( + address provider, + address outputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external + onlyOwner + override + { + ILiquidityProvider(provider).sellEthForToken( + outputToken, + recipient, + minBuyAmount, + auxiliaryData + ); + } + + /// @dev Calls `sellTokenForEth` on the given `provider` contract to + /// trigger a trade. + /// @param provider The address of the on-chain liquidity provider. + /// @param inputToken The token being sold. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of ETH to buy. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + function executeSellTokenForEth( + address provider, + address inputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external + onlyOwner + override + { + ILiquidityProvider(provider).sellTokenForEth( + inputToken, + payable(recipient), + minBuyAmount, + auxiliaryData + ); + } +} diff --git a/contracts/zero-ex/contracts/src/features/ILiquidityProviderFeature.sol b/contracts/zero-ex/contracts/src/features/ILiquidityProviderFeature.sol index 02792df8f6..0fee9e958f 100644 --- a/contracts/zero-ex/contracts/src/features/ILiquidityProviderFeature.sol +++ b/contracts/zero-ex/contracts/src/features/ILiquidityProviderFeature.sol @@ -22,45 +22,30 @@ pragma experimental ABIEncoderV2; /// @dev Feature to swap directly with an on-chain liquidity provider. interface ILiquidityProviderFeature { - event LiquidityProviderForMarketUpdated( - address indexed xAsset, - address indexed yAsset, - address providerAddress - ); + /// @dev Sells `sellAmount` of `inputToken` to the liquidity provider + /// at the given `provider` address. + /// @param inputToken The token being sold. + /// @param outputToken The token being bought. + /// @param provider The address of the on-chain liquidity provider + /// to trade with. + /// @param recipient The recipient of the bought tokens. If equal to + /// address(0), `msg.sender` is assumed to be the recipient. + /// @param sellAmount The amount of `inputToken` to sell. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to + /// buy. Reverts if this amount is not satisfied. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + /// @return boughtAmount The amount of `outputToken` bought. function sellToLiquidityProvider( - address makerToken, - address takerToken, - address payable recipient, + address inputToken, + address outputToken, + address payable provider, + address recipient, uint256 sellAmount, - uint256 minBuyAmount + uint256 minBuyAmount, + bytes calldata auxiliaryData ) external payable returns (uint256 boughtAmount); - - /// @dev Sets address of the liquidity provider for a market given - /// (xAsset, yAsset). - /// @param xAsset First asset managed by the liquidity provider. - /// @param yAsset Second asset managed by the liquidity provider. - /// @param providerAddress Address of the liquidity provider. - function setLiquidityProviderForMarket( - address xAsset, - address yAsset, - address providerAddress - ) - external; - - /// @dev Returns the address of the liquidity provider for a market given - /// (xAsset, yAsset), or reverts if pool does not exist. - /// @param xAsset First asset managed by the liquidity provider. - /// @param yAsset Second asset managed by the liquidity provider. - /// @return providerAddress Address of the liquidity provider. - function getLiquidityProviderForMarket( - address xAsset, - address yAsset - ) - external - view - returns (address providerAddress); } diff --git a/contracts/zero-ex/contracts/src/features/LiquidityProviderFeature.sol b/contracts/zero-ex/contracts/src/features/LiquidityProviderFeature.sol index 83b375e630..ca3e2728fc 100644 --- a/contracts/zero-ex/contracts/src/features/LiquidityProviderFeature.sol +++ b/contracts/zero-ex/contracts/src/features/LiquidityProviderFeature.sol @@ -20,15 +20,13 @@ pragma solidity ^0.6.5; pragma experimental ABIEncoderV2; import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; -import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol"; -import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; import "../errors/LibLiquidityProviderRichErrors.sol"; +import "../external/ILiquidityProviderSandbox.sol"; +import "../external/LiquidityProviderSandbox.sol"; import "../fixins/FixinCommon.sol"; import "../migrations/LibMigrate.sol"; -import "../storage/LibLiquidityProviderStorage.sol"; -import "../vendor/v3/IERC20Bridge.sol"; import "./IFeature.sol"; import "./ILiquidityProviderFeature.sol"; import "./libs/LibTokenSpender.sol"; @@ -39,7 +37,6 @@ contract LiquidityProviderFeature is ILiquidityProviderFeature, FixinCommon { - using LibERC20TokenV06 for IERC20TokenV06; using LibSafeMathV06 for uint256; using LibRichErrorsV06 for bytes; @@ -50,16 +47,24 @@ contract LiquidityProviderFeature is /// @dev ETH pseudo-token address. address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - /// @dev The WETH contract address. - IEtherTokenV06 public immutable weth; + /// @dev The sandbox contract address. + ILiquidityProviderSandbox public immutable sandbox; - /// @dev Store the WETH address in an immutable. - /// @param weth_ The weth token. - constructor(IEtherTokenV06 weth_) + /// @dev Event for data pipeline. + event LiquidityProviderSwap( + address inputToken, + address outputToken, + uint256 inputTokenAmount, + uint256 outputTokenAmount, + address provider, + address recipient + ); + + constructor(address zeroEx) public FixinCommon() { - weth = weth_; + sandbox = new LiquidityProviderSandbox(zeroEx); } /// @dev Initialize and register this feature. @@ -70,131 +75,102 @@ contract LiquidityProviderFeature is returns (bytes4 success) { _registerFeatureFunction(this.sellToLiquidityProvider.selector); - _registerFeatureFunction(this.setLiquidityProviderForMarket.selector); - _registerFeatureFunction(this.getLiquidityProviderForMarket.selector); return LibMigrate.MIGRATE_SUCCESS; } + /// @dev Sells `sellAmount` of `inputToken` to the liquidity provider + /// at the given `provider` address. + /// @param inputToken The token being sold. + /// @param outputToken The token being bought. + /// @param provider The address of the on-chain liquidity provider + /// to trade with. + /// @param recipient The recipient of the bought tokens. If equal to + /// address(0), `msg.sender` is assumed to be the recipient. + /// @param sellAmount The amount of `inputToken` to sell. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to + /// buy. Reverts if this amount is not satisfied. + /// @param auxiliaryData Auxiliary data supplied to the `provider` contract. + /// @return boughtAmount The amount of `outputToken` bought. function sellToLiquidityProvider( - address makerToken, - address takerToken, - address payable recipient, + address inputToken, + address outputToken, + address payable provider, + address recipient, uint256 sellAmount, - uint256 minBuyAmount + uint256 minBuyAmount, + bytes calldata auxiliaryData ) external override payable returns (uint256 boughtAmount) { - address providerAddress = getLiquidityProviderForMarket(makerToken, takerToken); if (recipient == address(0)) { recipient = msg.sender; } - if (takerToken == ETH_TOKEN_ADDRESS) { - // Wrap ETH. - weth.deposit{value: sellAmount}(); - weth.transfer(providerAddress, sellAmount); + if (inputToken == ETH_TOKEN_ADDRESS) { + provider.transfer(sellAmount); } else { LibTokenSpender.spendERC20Tokens( - IERC20TokenV06(takerToken), + IERC20TokenV06(inputToken), msg.sender, - providerAddress, + provider, sellAmount ); } - if (makerToken == ETH_TOKEN_ADDRESS) { - uint256 balanceBefore = weth.balanceOf(address(this)); - IERC20Bridge(providerAddress).bridgeTransferFrom( - address(weth), - address(0), - address(this), - minBuyAmount, - "" - ); - boughtAmount = weth.balanceOf(address(this)).safeSub(balanceBefore); - // Unwrap wETH and send ETH to recipient. - weth.withdraw(boughtAmount); - recipient.transfer(boughtAmount); - } else { - uint256 balanceBefore = IERC20TokenV06(makerToken).balanceOf(recipient); - IERC20Bridge(providerAddress).bridgeTransferFrom( - makerToken, - address(0), + if (inputToken == ETH_TOKEN_ADDRESS) { + uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient); + sandbox.executeSellEthForToken( + provider, + outputToken, recipient, minBuyAmount, - "" + auxiliaryData ); - boughtAmount = IERC20TokenV06(makerToken).balanceOf(recipient).safeSub(balanceBefore); + boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore); + } else if (outputToken == ETH_TOKEN_ADDRESS) { + uint256 balanceBefore = recipient.balance; + sandbox.executeSellTokenForEth( + provider, + inputToken, + recipient, + minBuyAmount, + auxiliaryData + ); + boughtAmount = recipient.balance.safeSub(balanceBefore); + } else { + uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient); + sandbox.executeSellTokenForToken( + provider, + inputToken, + outputToken, + recipient, + minBuyAmount, + auxiliaryData + ); + boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore); } + if (boughtAmount < minBuyAmount) { LibLiquidityProviderRichErrors.LiquidityProviderIncompleteSellError( - providerAddress, - makerToken, - takerToken, + provider, + outputToken, + inputToken, sellAmount, boughtAmount, minBuyAmount ).rrevert(); } - } - /// @dev Sets address of the liquidity provider for a market given - /// (xAsset, yAsset). - /// @param xAsset First asset managed by the liquidity provider. - /// @param yAsset Second asset managed by the liquidity provider. - /// @param providerAddress Address of the liquidity provider. - function setLiquidityProviderForMarket( - address xAsset, - address yAsset, - address providerAddress - ) - external - override - onlyOwner - { - LibLiquidityProviderStorage.getStorage() - .addressBook[xAsset][yAsset] = providerAddress; - LibLiquidityProviderStorage.getStorage() - .addressBook[yAsset][xAsset] = providerAddress; - emit LiquidityProviderForMarketUpdated( - xAsset, - yAsset, - providerAddress + emit LiquidityProviderSwap( + inputToken, + outputToken, + sellAmount, + boughtAmount, + provider, + recipient ); } - - /// @dev Returns the address of the liquidity provider for a market given - /// (xAsset, yAsset), or reverts if pool does not exist. - /// @param xAsset First asset managed by the liquidity provider. - /// @param yAsset Second asset managed by the liquidity provider. - /// @return providerAddress Address of the liquidity provider. - function getLiquidityProviderForMarket( - address xAsset, - address yAsset - ) - public - view - override - returns (address providerAddress) - { - if (xAsset == ETH_TOKEN_ADDRESS) { - providerAddress = LibLiquidityProviderStorage.getStorage() - .addressBook[address(weth)][yAsset]; - } else if (yAsset == ETH_TOKEN_ADDRESS) { - providerAddress = LibLiquidityProviderStorage.getStorage() - .addressBook[xAsset][address(weth)]; - } else { - providerAddress = LibLiquidityProviderStorage.getStorage() - .addressBook[xAsset][yAsset]; - } - if (providerAddress == address(0)) { - LibLiquidityProviderRichErrors.NoLiquidityProviderForMarketError( - xAsset, - yAsset - ).rrevert(); - } - } } diff --git a/contracts/zero-ex/contracts/src/features/TransformERC20Feature.sol b/contracts/zero-ex/contracts/src/features/TransformERC20Feature.sol index 99b63bacae..d02cedf785 100644 --- a/contracts/zero-ex/contracts/src/features/TransformERC20Feature.sol +++ b/contracts/zero-ex/contracts/src/features/TransformERC20Feature.sol @@ -58,7 +58,7 @@ contract TransformERC20Feature is /// @dev Name of this feature. string public constant override FEATURE_NAME = "TransformERC20"; /// @dev Version of this feature. - uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 0); + uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 3, 0); /// @dev Initialize and register this feature. /// Should be delegatecalled by `Migrate.migrate()`. diff --git a/contracts/zero-ex/contracts/src/features/UniswapFeature.sol b/contracts/zero-ex/contracts/src/features/UniswapFeature.sol index 2ac4f8aee0..9009902021 100644 --- a/contracts/zero-ex/contracts/src/features/UniswapFeature.sol +++ b/contracts/zero-ex/contracts/src/features/UniswapFeature.sol @@ -37,7 +37,7 @@ contract UniswapFeature is /// @dev Name of this feature. string public constant override FEATURE_NAME = "UniswapFeature"; /// @dev Version of this feature. - uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0); + uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0); /// @dev WETH contract. IEtherTokenV06 private immutable WETH; /// @dev AllowanceTarget instance. diff --git a/contracts/zero-ex/contracts/src/storage/LibLiquidityProviderStorage.sol b/contracts/zero-ex/contracts/src/storage/LibLiquidityProviderStorage.sol deleted file mode 100644 index 99f0361ef0..0000000000 --- a/contracts/zero-ex/contracts/src/storage/LibLiquidityProviderStorage.sol +++ /dev/null @@ -1,45 +0,0 @@ -/* - - Copyright 2020 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity ^0.6.5; -pragma experimental ABIEncoderV2; - -import "./LibStorage.sol"; - - -/// @dev Storage helpers for `LiquidityProviderFeature`. -library LibLiquidityProviderStorage { - - /// @dev Storage bucket for this feature. - struct Storage { - // Mapping of taker token -> maker token -> liquidity provider address - // Note that addressBook[x][y] == addressBook[y][x] will always hold. - mapping (address => mapping (address => address)) addressBook; - } - - /// @dev Get the storage bucket for this contract. - function getStorage() internal pure returns (Storage storage stor) { - uint256 storageSlot = LibStorage.getStorageSlot( - LibStorage.StorageId.LiquidityProvider - ); - // Dip into assembly to change the slot pointed to by the local - // variable `stor`. - // See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries - assembly { stor_slot := storageSlot } - } -} diff --git a/contracts/zero-ex/contracts/src/storage/LibStorage.sol b/contracts/zero-ex/contracts/src/storage/LibStorage.sol index 129254f82a..809977d4a8 100644 --- a/contracts/zero-ex/contracts/src/storage/LibStorage.sol +++ b/contracts/zero-ex/contracts/src/storage/LibStorage.sol @@ -36,8 +36,7 @@ library LibStorage { TokenSpender, TransformERC20, MetaTransactions, - ReentrancyGuard, - LiquidityProvider + ReentrancyGuard } /// @dev Get the storage slot given a storage ID. We assign unique, well-spaced diff --git a/contracts/zero-ex/contracts/test/TestBridge.sol b/contracts/zero-ex/contracts/test/TestBridge.sol index 4f94594649..f16b1c39a1 100644 --- a/contracts/zero-ex/contracts/test/TestBridge.sol +++ b/contracts/zero-ex/contracts/test/TestBridge.sol @@ -1,19 +1,15 @@ + /* - 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; diff --git a/contracts/zero-ex/contracts/test/TestFillQuoteTransformerBridge.sol b/contracts/zero-ex/contracts/test/TestFillQuoteTransformerBridge.sol index 7b8608ed2b..bc084a48e3 100644 --- a/contracts/zero-ex/contracts/test/TestFillQuoteTransformerBridge.sol +++ b/contracts/zero-ex/contracts/test/TestFillQuoteTransformerBridge.sol @@ -32,28 +32,26 @@ contract TestFillQuoteTransformerBridge { uint256 amount; } - bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3; - - function bridgeTransferFrom( - address tokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData + function sellTokenForToken( + address takerToken, + address makerToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData ) external - returns (bytes4 success) + returns (uint256 boughtAmount) { - FillBehavior memory behavior = abi.decode(bridgeData, (FillBehavior)); - TestMintableERC20Token(tokenAddress).mint( - to, - LibMathV06.getPartialAmountFloor( - behavior.makerAssetMintRatio, - 1e18, - behavior.amount - ) + FillBehavior memory behavior = abi.decode(auxiliaryData, (FillBehavior)); + boughtAmount = LibMathV06.getPartialAmountFloor( + behavior.makerAssetMintRatio, + 1e18, + behavior.amount + ); + TestMintableERC20Token(makerToken).mint( + recipient, + boughtAmount ); - return ERC20_BRIDGE_PROXY_ID; } function encodeBehaviorData(FillBehavior calldata behavior) diff --git a/contracts/zero-ex/contracts/test/TestLiquidityProvider.sol b/contracts/zero-ex/contracts/test/TestLiquidityProvider.sol new file mode 100644 index 0000000000..2a9884a09a --- /dev/null +++ b/contracts/zero-ex/contracts/test/TestLiquidityProvider.sol @@ -0,0 +1,135 @@ +/* + + 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/IERC20TokenV06.sol"; + + +contract TestLiquidityProvider { + event SellTokenForToken( + address inputToken, + address outputToken, + address recipient, + uint256 minBuyAmount, + uint256 inputTokenBalance + ); + + event SellEthForToken( + address outputToken, + address recipient, + uint256 minBuyAmount, + uint256 ethBalance + ); + + event SellTokenForEth( + address inputToken, + address recipient, + uint256 minBuyAmount, + uint256 inputTokenBalance + ); + + IERC20TokenV06 public immutable xAsset; + IERC20TokenV06 public immutable yAsset; + + constructor(IERC20TokenV06 xAsset_, IERC20TokenV06 yAsset_) + public + { + xAsset = xAsset_; + yAsset = yAsset_; + } + + receive() external payable {} + + /// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken` + /// to sell must be transferred to the contract prior to calling this + /// function to trigger the trade. + /// @param inputToken The token being sold. + /// @param outputToken The token being bought. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy. + /// @param auxiliaryData Arbitrary auxiliary data supplied to the contract. + /// @return boughtAmount The amount of `outputToken` bought. + function sellTokenForToken( + address inputToken, + address outputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external + returns (uint256 boughtAmount) + { + emit SellTokenForToken( + inputToken, + outputToken, + recipient, + minBuyAmount, + IERC20TokenV06(inputToken).balanceOf(address(this)) + ); + } + + /// @dev Trades ETH for token. ETH must be sent to the contract prior to + /// calling this function to trigger the trade. + /// @param outputToken The token being bought. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy. + /// @param auxiliaryData Arbitrary auxiliary data supplied to the contract. + /// @return boughtAmount The amount of `outputToken` bought. + function sellEthForToken( + address outputToken, + address recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external + returns (uint256 boughtAmount) + { + emit SellEthForToken( + outputToken, + recipient, + minBuyAmount, + address(this).balance + ); + } + + /// @dev Trades token for ETH. The token must be sent to the contract prior + /// to calling this function to trigger the trade. + /// @param inputToken The token being sold. + /// @param recipient The recipient of the bought tokens. + /// @param minBuyAmount The minimum acceptable amount of ETH to buy. + /// @param auxiliaryData Arbitrary auxiliary data supplied to the contract. + /// @return boughtAmount The amount of ETH bought. + function sellTokenForEth( + address inputToken, + address payable recipient, + uint256 minBuyAmount, + bytes calldata auxiliaryData + ) + external + returns (uint256 boughtAmount) + { + emit SellTokenForEth( + inputToken, + recipient, + minBuyAmount, + IERC20TokenV06(inputToken).balanceOf(address(this)) + ); + } +} diff --git a/contracts/zero-ex/package.json b/contracts/zero-ex/package.json index 73fca27b71..0b1b614b7d 100644 --- a/contracts/zero-ex/package.json +++ b/contracts/zero-ex/package.json @@ -40,9 +40,9 @@ "publish:private": "yarn build && gitpkg publish" }, "config": { - "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature", + "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProvider", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|IMetaTransactionsFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibLiquidityProviderStorage|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpender|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestLibSignature|TestLibTokenSpender|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestProtocolFees|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx).json" + "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpender|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestLibSignature|TestLibTokenSpender|TestLiquidityProvider|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestProtocolFees|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx).json" }, "repository": { "type": "git", diff --git a/contracts/zero-ex/src/artifacts.ts b/contracts/zero-ex/src/artifacts.ts index 9e41b7606f..cb7a510fb1 100644 --- a/contracts/zero-ex/src/artifacts.ts +++ b/contracts/zero-ex/src/artifacts.ts @@ -12,6 +12,7 @@ import * as FullMigration from '../generated-artifacts/FullMigration.json'; import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json'; import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.json'; import * as IFlashWallet from '../generated-artifacts/IFlashWallet.json'; +import * as ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json'; import * as InitialMigration from '../generated-artifacts/InitialMigration.json'; import * as IOwnableFeature from '../generated-artifacts/IOwnableFeature.json'; import * as ISimpleFunctionRegistryFeature from '../generated-artifacts/ISimpleFunctionRegistryFeature.json'; @@ -54,4 +55,5 @@ export const artifacts = { LogMetadataTransformer: LogMetadataTransformer as ContractArtifact, BridgeAdapter: BridgeAdapter as ContractArtifact, LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact, + ILiquidityProvider: ILiquidityProvider as ContractArtifact, }; diff --git a/contracts/zero-ex/src/wrappers.ts b/contracts/zero-ex/src/wrappers.ts index 0c88b3fa82..618b271096 100644 --- a/contracts/zero-ex/src/wrappers.ts +++ b/contracts/zero-ex/src/wrappers.ts @@ -10,6 +10,7 @@ export * from '../generated-wrappers/full_migration'; export * from '../generated-wrappers/i_allowance_target'; export * from '../generated-wrappers/i_erc20_transformer'; export * from '../generated-wrappers/i_flash_wallet'; +export * from '../generated-wrappers/i_liquidity_provider'; export * from '../generated-wrappers/i_ownable_feature'; export * from '../generated-wrappers/i_simple_function_registry_feature'; export * from '../generated-wrappers/i_token_spender_feature'; diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts index 70e515c973..59a6ee3831 100644 --- a/contracts/zero-ex/test/artifacts.ts +++ b/contracts/zero-ex/test/artifacts.ts @@ -28,6 +28,7 @@ import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json'; import * as IGasToken from '../test/generated-artifacts/IGasToken.json'; import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json'; import * as ILiquidityProviderFeature from '../test/generated-artifacts/ILiquidityProviderFeature.json'; +import * as ILiquidityProviderSandbox from '../test/generated-artifacts/ILiquidityProviderSandbox.json'; import * as IMetaTransactionsFeature from '../test/generated-artifacts/IMetaTransactionsFeature.json'; import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json'; import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json'; @@ -43,7 +44,6 @@ import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json'; import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json'; import * as LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.json'; import * as LibLiquidityProviderRichErrors from '../test/generated-artifacts/LibLiquidityProviderRichErrors.json'; -import * as LibLiquidityProviderStorage from '../test/generated-artifacts/LibLiquidityProviderStorage.json'; import * as LibMetaTransactionsRichErrors from '../test/generated-artifacts/LibMetaTransactionsRichErrors.json'; import * as LibMetaTransactionsStorage from '../test/generated-artifacts/LibMetaTransactionsStorage.json'; import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json'; @@ -66,6 +66,7 @@ import * as LibTransformERC20RichErrors from '../test/generated-artifacts/LibTra import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json'; import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json'; import * as LiquidityProviderFeature from '../test/generated-artifacts/LiquidityProviderFeature.json'; +import * as LiquidityProviderSandbox from '../test/generated-artifacts/LiquidityProviderSandbox.json'; import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json'; import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json'; import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json'; @@ -95,6 +96,7 @@ import * as TestFullMigration from '../test/generated-artifacts/TestFullMigratio import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.json'; import * as TestLibSignature from '../test/generated-artifacts/TestLibSignature.json'; import * as TestLibTokenSpender from '../test/generated-artifacts/TestLibTokenSpender.json'; +import * as TestLiquidityProvider from '../test/generated-artifacts/TestLiquidityProvider.json'; import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json'; import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json'; import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json'; @@ -137,6 +139,8 @@ export const artifacts = { FlashWallet: FlashWallet as ContractArtifact, IAllowanceTarget: IAllowanceTarget as ContractArtifact, IFlashWallet: IFlashWallet as ContractArtifact, + ILiquidityProviderSandbox: ILiquidityProviderSandbox as ContractArtifact, + LiquidityProviderSandbox: LiquidityProviderSandbox as ContractArtifact, TransformerDeployer: TransformerDeployer as ContractArtifact, BootstrapFeature: BootstrapFeature as ContractArtifact, IBootstrapFeature: IBootstrapFeature as ContractArtifact, @@ -168,7 +172,6 @@ export const artifacts = { InitialMigration: InitialMigration as ContractArtifact, LibBootstrap: LibBootstrap as ContractArtifact, LibMigrate: LibMigrate as ContractArtifact, - LibLiquidityProviderStorage: LibLiquidityProviderStorage as ContractArtifact, LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact, LibOwnableStorage: LibOwnableStorage as ContractArtifact, LibProxyStorage: LibProxyStorage as ContractArtifact, @@ -217,6 +220,7 @@ export const artifacts = { TestInitialMigration: TestInitialMigration as ContractArtifact, TestLibSignature: TestLibSignature as ContractArtifact, TestLibTokenSpender: TestLibTokenSpender as ContractArtifact, + TestLiquidityProvider: TestLiquidityProvider as ContractArtifact, TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact, TestMigrator: TestMigrator as ContractArtifact, TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact, diff --git a/contracts/zero-ex/test/features/liquidity_provider_test.ts b/contracts/zero-ex/test/features/liquidity_provider_test.ts index 520075aa28..25b696475d 100644 --- a/contracts/zero-ex/test/features/liquidity_provider_test.ts +++ b/contracts/zero-ex/test/features/liquidity_provider_test.ts @@ -1,16 +1,25 @@ import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { blockchainTests, constants, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils'; +import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; import { BigNumber, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils'; import { IOwnableFeatureContract, IZeroExContract, LiquidityProviderFeatureContract } from '../../src/wrappers'; import { artifacts } from '../artifacts'; import { abis } from '../utils/abis'; import { fullMigrateAsync } from '../utils/migration'; -import { IERC20BridgeEvents, TestBridgeContract, TestWethContract } from '../wrappers'; +import { + LiquidityProviderSandboxContract, + TestBridgeContract, + TestBridgeEvents, + TestLiquidityProviderContract, + TestLiquidityProviderEvents, + TestWethContract, +} from '../wrappers'; blockchainTests('LiquidityProvider feature', env => { let zeroEx: IZeroExContract; let feature: LiquidityProviderFeatureContract; + let sandbox: LiquidityProviderSandboxContract; + let liquidityProvider: TestLiquidityProviderContract; let token: DummyERC20TokenContract; let weth: TestWethContract; let owner: string; @@ -47,102 +56,112 @@ blockchainTests('LiquidityProvider feature', env => { env.provider, env.txDefaults, artifacts, - weth.address, + zeroEx.address, + ); + sandbox = new LiquidityProviderSandboxContract( + await featureImpl.sandbox().callAsync(), + env.provider, + env.txDefaults, ); await new IOwnableFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis) .migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner) .awaitTransactionSuccessAsync(); + + liquidityProvider = await TestLiquidityProviderContract.deployFrom0xArtifactAsync( + artifacts.TestLiquidityProvider, + env.provider, + env.txDefaults, + artifacts, + token.address, + weth.address, + ); }); - describe('Registry', () => { - it('`getLiquidityProviderForMarket` reverts if address is not set', async () => { - const [xAsset, yAsset] = [randomAddress(), randomAddress()]; - let tx = feature.getLiquidityProviderForMarket(xAsset, yAsset).awaitTransactionSuccessAsync(); - expect(tx).to.revertWith( - new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset), - ); - tx = feature.getLiquidityProviderForMarket(yAsset, xAsset).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith( - new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(yAsset, xAsset), - ); - }); - it('can set/get a liquidity provider address for a given market', async () => { - const expectedAddress = randomAddress(); - await feature - .setLiquidityProviderForMarket(token.address, weth.address, expectedAddress) - .awaitTransactionSuccessAsync(); - let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync(); - expect(actualAddress).to.equal(expectedAddress); - actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync(); - expect(actualAddress).to.equal(expectedAddress); - }); - it('can update a liquidity provider address for a given market', async () => { - const expectedAddress = randomAddress(); - await feature - .setLiquidityProviderForMarket(token.address, weth.address, expectedAddress) - .awaitTransactionSuccessAsync(); - let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync(); - expect(actualAddress).to.equal(expectedAddress); - actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync(); - expect(actualAddress).to.equal(expectedAddress); - }); - it('can effectively remove a liquidity provider for a market by setting the address to 0', async () => { - await feature - .setLiquidityProviderForMarket(token.address, weth.address, constants.NULL_ADDRESS) - .awaitTransactionSuccessAsync(); - const tx = feature - .getLiquidityProviderForMarket(token.address, weth.address) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith( - new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(token.address, weth.address), - ); - }); - it('reverts if non-owner attempts to set an address', async () => { - const tx = feature - .setLiquidityProviderForMarket(randomAddress(), randomAddress(), randomAddress()) + blockchainTests.resets('Sandbox', () => { + it('Cannot call sandbox `executeSellTokenForToken` function directly', async () => { + const tx = sandbox + .executeSellTokenForToken( + liquidityProvider.address, + token.address, + weth.address, + taker, + constants.ZERO_AMOUNT, + constants.NULL_BYTES, + ) .awaitTransactionSuccessAsync({ from: taker }); - return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker, owner)); + return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker)); + }); + it('Cannot call sandbox `executeSellEthForToken` function directly', async () => { + const tx = sandbox + .executeSellEthForToken( + liquidityProvider.address, + token.address, + taker, + constants.ZERO_AMOUNT, + constants.NULL_BYTES, + ) + .awaitTransactionSuccessAsync({ from: taker }); + return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker)); + }); + it('Cannot call sandbox `executeSellTokenForEth` function directly', async () => { + const tx = sandbox + .executeSellTokenForEth( + liquidityProvider.address, + token.address, + taker, + constants.ZERO_AMOUNT, + constants.NULL_BYTES, + ) + .awaitTransactionSuccessAsync({ from: taker }); + return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker)); }); }); blockchainTests.resets('Swap', () => { - let liquidityProvider: TestBridgeContract; const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; - before(async () => { - liquidityProvider = await TestBridgeContract.deployFrom0xArtifactAsync( + it('Successfully executes an ERC20-ERC20 swap', async () => { + const tx = await feature + .sellToLiquidityProvider( + token.address, + weth.address, + liquidityProvider.address, + constants.NULL_ADDRESS, + constants.ONE_ETHER, + constants.ZERO_AMOUNT, + constants.NULL_BYTES, + ) + .awaitTransactionSuccessAsync({ from: taker }); + verifyEventsFromLogs( + tx.logs, + [ + { + inputToken: token.address, + outputToken: weth.address, + recipient: taker, + minBuyAmount: constants.ZERO_AMOUNT, + inputTokenBalance: constants.ONE_ETHER, + }, + ], + TestLiquidityProviderEvents.SellTokenForToken, + ); + }); + it('Successfully executes an ERC20-ERC20 swap (backwards-compatibility)', async () => { + const bridge = await TestBridgeContract.deployFrom0xArtifactAsync( artifacts.TestBridge, env.provider, env.txDefaults, artifacts, - token.address, weth.address, + token.address, ); - await feature - .setLiquidityProviderForMarket(token.address, weth.address, liquidityProvider.address) - .awaitTransactionSuccessAsync(); - }); - it('Cannot execute a swap for a market without a liquidity provider set', async () => { - const [xAsset, yAsset] = [randomAddress(), randomAddress()]; - const tx = feature - .sellToLiquidityProvider( - xAsset, - yAsset, - constants.NULL_ADDRESS, - constants.ONE_ETHER, - constants.ZERO_AMOUNT, - ) - .awaitTransactionSuccessAsync({ from: taker }); - return expect(tx).to.revertWith( - new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset), - ); - }); - it('Successfully executes an ERC20-ERC20 swap', async () => { const tx = await feature .sellToLiquidityProvider( - weth.address, token.address, + weth.address, + bridge.address, constants.NULL_ADDRESS, constants.ONE_ETHER, constants.ZERO_AMOUNT, + constants.NULL_BYTES, ) .awaitTransactionSuccessAsync({ from: taker }); verifyEventsFromLogs( @@ -153,22 +172,24 @@ blockchainTests('LiquidityProvider feature', env => { outputToken: weth.address, inputTokenAmount: constants.ONE_ETHER, outputTokenAmount: constants.ZERO_AMOUNT, - from: constants.NULL_ADDRESS, + from: bridge.address, to: taker, }, ], - IERC20BridgeEvents.ERC20BridgeTransfer, + TestBridgeEvents.ERC20BridgeTransfer, ); }); it('Reverts if cannot fulfill the minimum buy amount', async () => { const minBuyAmount = new BigNumber(1); const tx = feature .sellToLiquidityProvider( - weth.address, token.address, + weth.address, + liquidityProvider.address, constants.NULL_ADDRESS, constants.ONE_ETHER, minBuyAmount, + constants.NULL_BYTES, ) .awaitTransactionSuccessAsync({ from: taker }); return expect(tx).to.revertWith( @@ -185,36 +206,38 @@ blockchainTests('LiquidityProvider feature', env => { it('Successfully executes an ETH-ERC20 swap', async () => { const tx = await feature .sellToLiquidityProvider( - token.address, ETH_TOKEN_ADDRESS, + token.address, + liquidityProvider.address, constants.NULL_ADDRESS, constants.ONE_ETHER, constants.ZERO_AMOUNT, + constants.NULL_BYTES, ) .awaitTransactionSuccessAsync({ from: taker, value: constants.ONE_ETHER }); verifyEventsFromLogs( tx.logs, [ { - inputToken: weth.address, outputToken: token.address, - inputTokenAmount: constants.ONE_ETHER, - outputTokenAmount: constants.ZERO_AMOUNT, - from: constants.NULL_ADDRESS, - to: taker, + recipient: taker, + minBuyAmount: constants.ZERO_AMOUNT, + ethBalance: constants.ONE_ETHER, }, ], - IERC20BridgeEvents.ERC20BridgeTransfer, + TestLiquidityProviderEvents.SellEthForToken, ); }); it('Successfully executes an ERC20-ETH swap', async () => { const tx = await feature .sellToLiquidityProvider( - ETH_TOKEN_ADDRESS, token.address, + ETH_TOKEN_ADDRESS, + liquidityProvider.address, constants.NULL_ADDRESS, constants.ONE_ETHER, constants.ZERO_AMOUNT, + constants.NULL_BYTES, ) .awaitTransactionSuccessAsync({ from: taker }); verifyEventsFromLogs( @@ -222,14 +245,12 @@ blockchainTests('LiquidityProvider feature', env => { [ { inputToken: token.address, - outputToken: weth.address, - inputTokenAmount: constants.ONE_ETHER, - outputTokenAmount: constants.ZERO_AMOUNT, - from: constants.NULL_ADDRESS, - to: zeroEx.address, + recipient: taker, + minBuyAmount: constants.ZERO_AMOUNT, + inputTokenBalance: constants.ONE_ETHER, }, ], - IERC20BridgeEvents.ERC20BridgeTransfer, + TestLiquidityProviderEvents.SellTokenForEth, ); }); }); diff --git a/contracts/zero-ex/test/wrappers.ts b/contracts/zero-ex/test/wrappers.ts index 1c814c2b4a..5dc09b723b 100644 --- a/contracts/zero-ex/test/wrappers.ts +++ b/contracts/zero-ex/test/wrappers.ts @@ -26,6 +26,7 @@ export * from '../test/generated-wrappers/i_flash_wallet'; export * from '../test/generated-wrappers/i_gas_token'; export * from '../test/generated-wrappers/i_liquidity_provider'; export * from '../test/generated-wrappers/i_liquidity_provider_feature'; +export * from '../test/generated-wrappers/i_liquidity_provider_sandbox'; export * from '../test/generated-wrappers/i_meta_transactions_feature'; export * from '../test/generated-wrappers/i_ownable_feature'; export * from '../test/generated-wrappers/i_signature_validator_feature'; @@ -41,7 +42,6 @@ export * from '../test/generated-wrappers/lib_bootstrap'; export * from '../test/generated-wrappers/lib_common_rich_errors'; export * from '../test/generated-wrappers/lib_erc20_transformer'; export * from '../test/generated-wrappers/lib_liquidity_provider_rich_errors'; -export * from '../test/generated-wrappers/lib_liquidity_provider_storage'; export * from '../test/generated-wrappers/lib_meta_transactions_rich_errors'; export * from '../test/generated-wrappers/lib_meta_transactions_storage'; export * from '../test/generated-wrappers/lib_migrate'; @@ -64,6 +64,7 @@ export * from '../test/generated-wrappers/lib_transform_erc20_rich_errors'; export * from '../test/generated-wrappers/lib_transform_erc20_storage'; export * from '../test/generated-wrappers/lib_wallet_rich_errors'; export * from '../test/generated-wrappers/liquidity_provider_feature'; +export * from '../test/generated-wrappers/liquidity_provider_sandbox'; export * from '../test/generated-wrappers/log_metadata_transformer'; export * from '../test/generated-wrappers/meta_transactions_feature'; export * from '../test/generated-wrappers/mixin_adapter_addresses'; @@ -93,6 +94,7 @@ export * from '../test/generated-wrappers/test_full_migration'; export * from '../test/generated-wrappers/test_initial_migration'; export * from '../test/generated-wrappers/test_lib_signature'; export * from '../test/generated-wrappers/test_lib_token_spender'; +export * from '../test/generated-wrappers/test_liquidity_provider'; export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20_feature'; export * from '../test/generated-wrappers/test_migrator'; export * from '../test/generated-wrappers/test_mint_token_erc20_transformer'; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json index b27a4223f6..78e2cc5832 100644 --- a/contracts/zero-ex/tsconfig.json +++ b/contracts/zero-ex/tsconfig.json @@ -10,6 +10,7 @@ "generated-artifacts/IAllowanceTarget.json", "generated-artifacts/IERC20Transformer.json", "generated-artifacts/IFlashWallet.json", + "generated-artifacts/ILiquidityProvider.json", "generated-artifacts/IOwnableFeature.json", "generated-artifacts/ISimpleFunctionRegistryFeature.json", "generated-artifacts/ITokenSpenderFeature.json", @@ -50,6 +51,7 @@ "test/generated-artifacts/IGasToken.json", "test/generated-artifacts/ILiquidityProvider.json", "test/generated-artifacts/ILiquidityProviderFeature.json", + "test/generated-artifacts/ILiquidityProviderSandbox.json", "test/generated-artifacts/IMetaTransactionsFeature.json", "test/generated-artifacts/IOwnableFeature.json", "test/generated-artifacts/ISignatureValidatorFeature.json", @@ -65,7 +67,6 @@ "test/generated-artifacts/LibCommonRichErrors.json", "test/generated-artifacts/LibERC20Transformer.json", "test/generated-artifacts/LibLiquidityProviderRichErrors.json", - "test/generated-artifacts/LibLiquidityProviderStorage.json", "test/generated-artifacts/LibMetaTransactionsRichErrors.json", "test/generated-artifacts/LibMetaTransactionsStorage.json", "test/generated-artifacts/LibMigrate.json", @@ -88,6 +89,7 @@ "test/generated-artifacts/LibTransformERC20Storage.json", "test/generated-artifacts/LibWalletRichErrors.json", "test/generated-artifacts/LiquidityProviderFeature.json", + "test/generated-artifacts/LiquidityProviderSandbox.json", "test/generated-artifacts/LogMetadataTransformer.json", "test/generated-artifacts/MetaTransactionsFeature.json", "test/generated-artifacts/MixinAdapterAddresses.json", @@ -117,6 +119,7 @@ "test/generated-artifacts/TestInitialMigration.json", "test/generated-artifacts/TestLibSignature.json", "test/generated-artifacts/TestLibTokenSpender.json", + "test/generated-artifacts/TestLiquidityProvider.json", "test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json", "test/generated-artifacts/TestMigrator.json", "test/generated-artifacts/TestMintTokenERC20Transformer.json", diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index f53df7fe6b..8e6b96cd14 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -1,4 +1,17 @@ [ + { + "version": "5.1.0", + "changes": [ + { + "note": "Add support for LiquidityProvider feature in the swap quote consumer", + "pr": 16 + }, + { + "note": "Remove support for MultiBridge 😞", + "pr": 16 + } + ] + }, { "timestamp": 1604620645, "version": "5.0.3", diff --git a/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol b/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol index a64fb347fb..123865a241 100644 --- a/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol +++ b/packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol @@ -20,8 +20,7 @@ pragma solidity ^0.6; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; -import "./interfaces/ILiquidityProvider.sol"; -import "./interfaces/ILiquidityProviderRegistry.sol"; +import "@0x/contracts-zero-ex/contracts/src/vendor/ILiquidityProvider.sol"; import "./ApproximateBuys.sol"; import "./SamplerUtils.sol"; @@ -34,37 +33,26 @@ contract LiquidityProviderSampler is uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k /// @dev Sample sell quotes from an arbitrary on-chain liquidity provider. - /// @param registryAddress Address of the liquidity provider registry contract. + /// @param providerAddress Address of the liquidity provider. /// @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 makerTokenAmounts Maker amounts bought at each taker token /// amount. - function sampleSellsFromLiquidityProviderRegistry( - address registryAddress, + function sampleSellsFromLiquidityProvider( + address providerAddress, address takerToken, address makerToken, uint256[] memory takerTokenAmounts ) public view - returns (uint256[] memory makerTokenAmounts, address providerAddress) + returns (uint256[] memory makerTokenAmounts) { // Initialize array of maker token amounts. uint256 numSamples = takerTokenAmounts.length; makerTokenAmounts = new uint256[](numSamples); - // Query registry for provider address. - providerAddress = _getLiquidityProviderFromRegistry( - registryAddress, - takerToken, - makerToken - ); - // If provider doesn't exist, return all zeros. - if (providerAddress == address(0)) { - return (makerTokenAmounts, providerAddress); - } - for (uint256 i = 0; i < numSamples; i++) { try ILiquidityProvider(providerAddress).getSellQuote @@ -81,68 +69,33 @@ contract LiquidityProviderSampler is } /// @dev Sample buy quotes from an arbitrary on-chain liquidity provider. - /// @param registryAddress Address of the liquidity provider registry contract. + /// @param providerAddress Address of the liquidity provider. /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). /// @param makerTokenAmounts Maker token buy amount for each sample. /// @return takerTokenAmounts Taker amounts sold at each maker token /// amount. - function sampleBuysFromLiquidityProviderRegistry( - address registryAddress, + function sampleBuysFromLiquidityProvider( + address providerAddress, address takerToken, address makerToken, uint256[] memory makerTokenAmounts ) public view - returns (uint256[] memory takerTokenAmounts, address providerAddress) + returns (uint256[] memory takerTokenAmounts) { - providerAddress = _getLiquidityProviderFromRegistry( - registryAddress, - takerToken, - makerToken - ); takerTokenAmounts = _sampleApproximateBuys( ApproximateBuyQuoteOpts({ - makerTokenData: abi.encode(makerToken, registryAddress), - takerTokenData: abi.encode(takerToken, registryAddress), - getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProviderRegistry + makerTokenData: abi.encode(makerToken, providerAddress), + takerTokenData: abi.encode(takerToken, providerAddress), + getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProvider }), makerTokenAmounts ); } - /// @dev Returns the address of a liquidity provider for the given market - /// (takerToken, makerToken), from a registry of liquidity providers. - /// Returns address(0) if no such provider exists in the registry. - /// @param takerToken Taker asset managed by liquidity provider. - /// @param makerToken Maker asset managed by liquidity provider. - /// @return providerAddress Address of the liquidity provider. - function _getLiquidityProviderFromRegistry( - address registryAddress, - address takerToken, - address makerToken - ) - private - view - returns (address providerAddress) - { - if (registryAddress == address(0)) { - return address(0); - } - - bytes memory callData = abi.encodeWithSelector( - ILiquidityProviderRegistry.getLiquidityProviderForMarket.selector, - takerToken, - makerToken - ); - (bool didSucceed, bytes memory returnData) = registryAddress.staticcall(callData); - if (didSucceed && returnData.length == 32) { - return LibBytesV06.readAddress(returnData, 12); - } - } - - function _sampleSellForApproximateBuyFromLiquidityProviderRegistry( + function _sampleSellForApproximateBuyFromLiquidityProvider( bytes memory takerTokenData, bytes memory makerTokenData, uint256 sellAmount @@ -151,15 +104,15 @@ contract LiquidityProviderSampler is view returns (uint256 buyAmount) { - (address takerToken, address plpRegistryAddress) = + (address takerToken, address providerAddress) = abi.decode(takerTokenData, (address, address)); (address makerToken) = abi.decode(makerTokenData, (address)); try - this.sampleSellsFromLiquidityProviderRegistry + this.sampleSellsFromLiquidityProvider {gas: DEFAULT_CALL_GAS} - (plpRegistryAddress, takerToken, makerToken, _toSingleValueArray(sellAmount)) - returns (uint256[] memory amounts, address) + (providerAddress, takerToken, makerToken, _toSingleValueArray(sellAmount)) + returns (uint256[] memory amounts) { return amounts[0]; } catch (bytes memory) { diff --git a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol b/packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol deleted file mode 100644 index c07a8ebfff..0000000000 --- a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProvider.sol +++ /dev/null @@ -1,70 +0,0 @@ -/* - - Copyright 2020 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity ^0.6; - - -interface ILiquidityProvider { - - /// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`. - /// @param tokenAddress The address of the ERC20 token to transfer. - /// @param from Address to transfer asset from. - /// @param to Address to transfer asset to. - /// @param amount Amount of asset to transfer. - /// @param bridgeData Arbitrary asset data needed by the bridge contract. - /// @return success The magic bytes `0xdc1600f3` if successful. - function bridgeTransferFrom( - address tokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success); - - /// @dev Quotes the amount of `makerToken` that would be obtained by - /// selling `sellAmount` of `takerToken`. - /// @param takerToken Address of the taker token (what to sell). - /// @param makerToken Address of the maker token (what to buy). - /// @param sellAmount Amount of `takerToken` to sell. - /// @return makerTokenAmount Amount of `makerToken` that would be obtained. - function getSellQuote( - address takerToken, - address makerToken, - uint256 sellAmount - ) - external - view - returns (uint256 makerTokenAmount); - - /// @dev Quotes the amount of `takerToken` that would need to be sold in - /// order to obtain `buyAmount` of `makerToken`. - /// @param takerToken Address of the taker token (what to sell). - /// @param makerToken Address of the maker token (what to buy). - /// @param buyAmount Amount of `makerToken` to buy. - /// @return takerTokenAmount Amount of `takerToken` that would need to be sold. - function getBuyQuote( - address takerToken, - address makerToken, - uint256 buyAmount - ) - external - view - returns (uint256 takerTokenAmount); -} diff --git a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol b/packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol deleted file mode 100644 index 0ad8c4cb6f..0000000000 --- a/packages/asset-swapper/contracts/src/interfaces/ILiquidityProviderRegistry.sol +++ /dev/null @@ -1,36 +0,0 @@ -/* - - Copyright 2020 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity ^0.6; - - -interface ILiquidityProviderRegistry { - - /// @dev Returns the address of a liquidity provider for the given market - /// (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 providerAddress Address of the liquidity provider. - function getLiquidityProviderForMarket( - address takerToken, - address makerToken - ) - external - view - returns (address providerAddress); -} diff --git a/packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol b/packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol deleted file mode 100644 index a45aed5e59..0000000000 --- a/packages/asset-swapper/contracts/test/DummyLiquidityProviderRegistry.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.6; -pragma experimental ABIEncoderV2; - - -contract DummyLiquidityProviderRegistry -{ - address private constant NULL_ADDRESS = address(0x0); - - mapping (address => mapping (address => address)) internal _gAddressBook; - - /// @dev Sets address of pool for a market given market (xAsset, yAsset). - /// @param xToken First asset managed by pool. - /// @param yToken Second asset managed by pool. - /// @param poolAddress Address of pool. - function setLiquidityProviderForMarket( - address xToken, - address yToken, - address poolAddress - ) - external - { - _gAddressBook[xToken][yToken] = poolAddress; - _gAddressBook[yToken][xToken] = poolAddress; - } - - /// @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 poolAddress Address of pool. - function getLiquidityProviderForMarket( - address xToken, - address yToken - ) - external - view - returns (address poolAddress) - { - poolAddress = _gAddressBook[xToken][yToken]; - require( - poolAddress != NULL_ADDRESS, - "Registry/MARKET_PAIR_NOT_SET" - ); - } -} diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index b9343bc635..753d2e0eb0 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -36,9 +36,9 @@ "publish:private": "yarn build && gitpkg publish" }, "config": { - "publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider", + "publicInterfaceContracts": "ERC20BridgeSampler", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "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", + "abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json", "postpublish": { "assets": [] } @@ -94,6 +94,7 @@ "@0x/contracts-gen": "^2.0.18", "@0x/contracts-test-utils": "^5.3.10", "@0x/contracts-utils": "^4.5.7", + "@0x/contracts-zero-ex": "^0.8.0", "@0x/mesh-rpc-client": "^9.4.2", "@0x/migrations": "^6.4.7", "@0x/sol-compiler": "^4.2.7", diff --git a/packages/asset-swapper/src/artifacts.ts b/packages/asset-swapper/src/artifacts.ts index 249ae04744..7cb876ed6c 100644 --- a/packages/asset-swapper/src/artifacts.ts +++ b/packages/asset-swapper/src/artifacts.ts @@ -5,15 +5,5 @@ */ import { ContractArtifact } from 'ethereum-types'; -import * as DummyLiquidityProvider from '../generated-artifacts/DummyLiquidityProvider.json'; -import * as DummyLiquidityProviderRegistry from '../generated-artifacts/DummyLiquidityProviderRegistry.json'; import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json'; -import * as ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json'; -import * as ILiquidityProviderRegistry from '../generated-artifacts/ILiquidityProviderRegistry.json'; -export const artifacts = { - ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact, - ILiquidityProvider: ILiquidityProvider as ContractArtifact, - ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact, - DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact, - DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact, -}; +export const artifacts = { ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact }; diff --git a/packages/asset-swapper/src/index.ts b/packages/asset-swapper/src/index.ts index 24fb8cfc97..0e3e273728 100644 --- a/packages/asset-swapper/src/index.ts +++ b/packages/asset-swapper/src/index.ts @@ -147,10 +147,10 @@ export { GetMarketOrdersRfqtOpts, KyberFillData, LiquidityProviderFillData, + LiquidityProviderRegistry, MarketDepth, MarketDepthSide, MooniswapFillData, - MultiBridgeFillData, MultiHopFillData, NativeCollapsedFill, NativeFillData, diff --git a/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts b/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts index 14e0bc7d72..b89b965a3f 100644 --- a/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts +++ b/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts @@ -34,7 +34,7 @@ import { getSwapMinBuyAmount } from './utils'; // tslint:disable-next-line:custom-no-magic-numbers const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); -const { NULL_ADDRESS, ZERO_AMOUNT } = constants; +const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants; export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { public readonly provider: ZeroExProvider; @@ -96,9 +96,16 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { const buyToken = getTokenFromAssetData(quote.makerAssetData); const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount; let minBuyAmount = getSwapMinBuyAmount(quote); + let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount; + if (isFromETH) { + ethAmount = ethAmount.plus(sellAmount); + } + const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee; // VIP routes. - if (isDirectUniswapCompatible(quote, optsWithDefaults)) { + if ( + isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap]) + ) { const source = quote.orders[0].fills[0].source; const fillData = quote.orders[0].fills[0].fillData as UniswapV2FillData; return { @@ -124,6 +131,26 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { }; } + if (isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.LiquidityProvider])) { + const target = quote.orders[0].makerAddress; + return { + calldataHexString: this._exchangeProxy + .sellToLiquidityProvider( + isFromETH ? ETH_TOKEN_ADDRESS : sellToken, + isToETH ? ETH_TOKEN_ADDRESS : buyToken, + target, + NULL_ADDRESS, + sellAmount, + minBuyAmount, + NULL_BYTES, + ) + .getABIEncodedTransactionData(), + ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT, + toAddress: this._exchangeProxy.address, + allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget, + }; + } + // Build up the transforms. const transforms = []; if (isFromETH) { @@ -198,8 +225,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { } // This transformer pays affiliate fees. - const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee; - if (buyTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) { transforms.push({ deploymentNonce: this.transformerNonces.affiliateFeeTransformer, @@ -216,7 +241,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { // Adjust the minimum buy amount by the fee. minBuyAmount = BigNumber.max(0, minBuyAmount.minus(buyTokenFeeAmount)); } - if (sellTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) { throw new Error('Affiliate fees denominated in sell token are not yet supported'); } @@ -240,11 +264,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { ) .getABIEncodedTransactionData(); - let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount; - if (isFromETH) { - ethAmount = ethAmount.plus(sellAmount); - } - return { calldataHexString, ethAmount, @@ -266,7 +285,11 @@ function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote { return quote.type === MarketOperation.Buy; } -function isDirectUniswapCompatible(quote: SwapQuote, opts: ExchangeProxyContractOpts): boolean { +function isDirectSwapCompatible( + quote: SwapQuote, + opts: ExchangeProxyContractOpts, + directSources: ERC20BridgeSource[], +): boolean { // Must not be a mtx. if (opts.isMetaTransaction) { return false; @@ -285,8 +308,7 @@ function isDirectUniswapCompatible(quote: SwapQuote, opts: ExchangeProxyContract return false; } const fill = order.fills[0]; - // And that fill must be uniswap v2 or sushiswap. - if (![ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap].includes(fill.source)) { + if (!directSources.includes(fill.source)) { return false; } return true; diff --git a/packages/asset-swapper/src/quote_consumers/utils.ts b/packages/asset-swapper/src/quote_consumers/utils.ts index 67b2677acf..b085b20dbb 100644 --- a/packages/asset-swapper/src/quote_consumers/utils.ts +++ b/packages/asset-swapper/src/quote_consumers/utils.ts @@ -5,7 +5,7 @@ import { MarketOperation, SwapQuote } from '../types'; import { ERC20BridgeSource } from '../utils/market_operation_utils/types'; /** - * Compute the mminimum buy token amount for market operations by inferring + * Compute the minimum buy token amount for market operations by inferring * the slippage from the orders in a quote. We cannot rely on * `worstCaseQuoteInfo.makerAssetAmount` because that does not stop at * maximum slippage. diff --git a/packages/asset-swapper/src/swap_quoter.ts b/packages/asset-swapper/src/swap_quoter.ts index 38c0131ccf..c4cb88626a 100644 --- a/packages/asset-swapper/src/swap_quoter.ts +++ b/packages/asset-swapper/src/swap_quoter.ts @@ -165,8 +165,9 @@ export class SwapQuoter { expiryBufferMs, permittedOrderFeeTypes, samplerGasLimit, - liquidityProviderRegistryAddress, rfqt, + tokenAdjacencyGraph, + liquidityProviderRegistry, } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); const provider = providerUtils.standardizeOrThrow(supportedProvider); assert.isValidOrderbook('orderbook', orderbook); @@ -208,13 +209,21 @@ export class SwapQuoter { }, ); this._marketOperationUtils = new MarketOperationUtils( - new DexOrderSampler(samplerContract, samplerOverrides, provider), + new DexOrderSampler( + samplerContract, + samplerOverrides, + provider, + undefined, + undefined, + undefined, + tokenAdjacencyGraph, + liquidityProviderRegistry, + ), this._contractAddresses, { chainId, exchangeAddress: this._contractAddresses.exchange, }, - liquidityProviderRegistryAddress, ); this._swapQuoteCalculator = new SwapQuoteCalculator(this._marketOperationUtils); } diff --git a/packages/asset-swapper/src/types.ts b/packages/asset-swapper/src/types.ts index a31812d709..7259af1e74 100644 --- a/packages/asset-swapper/src/types.ts +++ b/packages/asset-swapper/src/types.ts @@ -4,7 +4,13 @@ import { TakerRequestQueryParams } from '@0x/quote-server'; import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import { ERC20BridgeSource, GetMarketOrdersOpts, OptimizedMarketOrder } from './utils/market_operation_utils/types'; +import { + ERC20BridgeSource, + GetMarketOrdersOpts, + LiquidityProviderRegistry, + OptimizedMarketOrder, + TokenAdjacencyGraph, +} from './utils/market_operation_utils/types'; import { QuoteReport } from './utils/quote_report_generator'; /** @@ -310,11 +316,12 @@ export interface SwapQuoterOpts extends OrderPrunerOpts { ethereumRpcUrl?: string; contractAddresses?: AssetSwapperContractAddresses; samplerGasLimit?: number; - liquidityProviderRegistryAddress?: string; multiBridgeAddress?: string; ethGasStationUrl?: string; rfqt?: SwapQuoterRfqtOpts; samplerOverrides?: SamplerOverrides; + tokenAdjacencyGraph?: TokenAdjacencyGraph; + liquidityProviderRegistry?: LiquidityProviderRegistry; } /** 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 c54cda9226..ee58d0cbdf 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -13,6 +13,7 @@ import { FeeSchedule, FillData, GetMarketOrdersOpts, + LiquidityProviderRegistry, MultiHopFillData, SnowSwapFillData, SushiSwapFillData, @@ -24,55 +25,51 @@ import { /** * 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, - ], - [ERC20BridgeSource.MultiBridge], -); +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.LiquidityProvider, +]); /** * Valid sources for market buy. */ -export const BUY_SOURCE_FILTER = new SourceFilters( - [ - ERC20BridgeSource.Native, - ERC20BridgeSource.Uniswap, - ERC20BridgeSource.UniswapV2, - ERC20BridgeSource.Eth2Dai, - ERC20BridgeSource.Kyber, - ERC20BridgeSource.Curve, - ERC20BridgeSource.Balancer, - // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports buy quotes - ERC20BridgeSource.MStable, - ERC20BridgeSource.Mooniswap, - ERC20BridgeSource.Shell, - ERC20BridgeSource.Swerve, - ERC20BridgeSource.SnowSwap, - ERC20BridgeSource.SushiSwap, - ERC20BridgeSource.MultiHop, - ERC20BridgeSource.Dodo, - ERC20BridgeSource.Cream, - ], - [ERC20BridgeSource.MultiBridge], -); +export const BUY_SOURCE_FILTER = new SourceFilters([ + ERC20BridgeSource.Native, + ERC20BridgeSource.Uniswap, + ERC20BridgeSource.UniswapV2, + ERC20BridgeSource.Eth2Dai, + ERC20BridgeSource.Kyber, + ERC20BridgeSource.Curve, + ERC20BridgeSource.Balancer, + // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports buy quotes + ERC20BridgeSource.MStable, + ERC20BridgeSource.Mooniswap, + ERC20BridgeSource.Shell, + ERC20BridgeSource.Swerve, + ERC20BridgeSource.SnowSwap, + ERC20BridgeSource.SushiSwap, + ERC20BridgeSource.MultiHop, + ERC20BridgeSource.Dodo, + ERC20BridgeSource.Cream, + ERC20BridgeSource.LiquidityProvider, +]); /** * 0x Protocol Fee Multiplier @@ -352,6 +349,8 @@ export const MAINNET_KYBER_TOKEN_RESERVE_IDS: { [token: string]: string } = { '0xaa42414e44000000000000000000000000000000000000000000000000000000', }; +export const LIQUIDITY_PROVIDER_REGISTRY: LiquidityProviderRegistry = {}; + export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F'; export const MAINNET_SHELL_POOLS = { @@ -544,5 +543,5 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = { exchangeProxyOverhead: () => ZERO_AMOUNT, allowFallback: true, shouldGenerateQuoteReport: false, - tokenAdjacencyGraph: {}, + tokenAdjacencyGraph: { default: [] }, }; 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 d9b58e2cdc..56ac3e52a0 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -78,7 +78,6 @@ export async function getRfqtIndicativeQuotesAsync( export class MarketOperationUtils { private readonly _wethAddress: string; - private readonly _multiBridge: string; private readonly _sellSources: SourceFilters; private readonly _buySources: SourceFilters; private readonly _feeSources = new SourceFilters(FEE_QUOTE_SOURCES); @@ -108,19 +107,10 @@ export class MarketOperationUtils { private readonly _sampler: DexOrderSampler, private readonly contractAddresses: AssetSwapperContractAddresses, private readonly _orderDomain: OrderDomain, - private readonly _liquidityProviderRegistry: string = NULL_ADDRESS, ) { this._wethAddress = contractAddresses.etherToken.toLowerCase(); - this._multiBridge = contractAddresses.multiBridge.toLowerCase(); - const optionalQuoteSources = []; - if (this._liquidityProviderRegistry !== NULL_ADDRESS) { - optionalQuoteSources.push(ERC20BridgeSource.LiquidityProvider); - } - if (this._multiBridge !== NULL_ADDRESS) { - optionalQuoteSources.push(ERC20BridgeSource.MultiBridge); - } - this._buySources = BUY_SOURCE_FILTER.validate(optionalQuoteSources); - this._sellSources = SELL_SOURCE_FILTER.validate(optionalQuoteSources); + this._buySources = BUY_SOURCE_FILTER; + this._sellSources = SELL_SOURCE_FILTER; } /** @@ -176,42 +166,21 @@ export class MarketOperationUtils { // Get native order fillable amounts. this._sampler.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchange), // Get ETH -> maker token price. - this._sampler.getMedianSellRate( - feeSourceFilters.sources, - makerToken, - this._wethAddress, - ONE_ETHER, - this._liquidityProviderRegistry, - this._multiBridge, - ), + this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER), // Get ETH -> taker token price. - this._sampler.getMedianSellRate( - feeSourceFilters.sources, - takerToken, - this._wethAddress, - ONE_ETHER, - this._liquidityProviderRegistry, - this._multiBridge, - ), + this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER), // Get sell quotes for taker -> maker. this._sampler.getSellQuotes( quoteSourceFilters.exclude(offChainSources).sources, makerToken, takerToken, sampleAmounts, - this._wethAddress, - _opts.tokenAdjacencyGraph, - this._liquidityProviderRegistry, - this._multiBridge, ), this._sampler.getTwoHopSellQuotes( quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [], makerToken, takerToken, takerAmount, - this._wethAddress, - _opts.tokenAdjacencyGraph, - this._liquidityProviderRegistry, ), ); @@ -327,41 +296,21 @@ export class MarketOperationUtils { // Get native order fillable amounts. this._sampler.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchange), // Get ETH -> makerToken token price. - this._sampler.getMedianSellRate( - feeSourceFilters.sources, - makerToken, - this._wethAddress, - ONE_ETHER, - this._liquidityProviderRegistry, - this._multiBridge, - ), + this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER), // Get ETH -> taker token price. - this._sampler.getMedianSellRate( - feeSourceFilters.sources, - takerToken, - this._wethAddress, - ONE_ETHER, - this._liquidityProviderRegistry, - this._multiBridge, - ), + this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER), // Get buy quotes for taker -> maker. this._sampler.getBuyQuotes( quoteSourceFilters.exclude(offChainSources).sources, makerToken, takerToken, sampleAmounts, - this._wethAddress, - _opts.tokenAdjacencyGraph, - this._liquidityProviderRegistry, ), this._sampler.getTwoHopBuyQuotes( quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [], makerToken, takerToken, makerAmount, - this._wethAddress, - _opts.tokenAdjacencyGraph, - this._liquidityProviderRegistry, ), ); const isPriceAwareRfqEnabled = @@ -391,10 +340,6 @@ export class MarketOperationUtils { offChainBalancerQuotes, offChainCreamQuotes, ] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainCreamPromise]); - // Attach the MultiBridge address to the sample fillData - (dexQuotes.find(quotes => quotes[0] && quotes[0].source === ERC20BridgeSource.MultiBridge) || []).forEach( - q => (q.fillData = { poolAddress: this._multiBridge }), - ); const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals; return { side: MarketOperation.Buy, @@ -482,7 +427,6 @@ export class MarketOperationUtils { getNativeOrderTokens(orders[0])[1], this._wethAddress, ONE_ETHER, - this._wethAddress, ), ), ...batchNativeOrders.map((orders, i) => @@ -491,8 +435,6 @@ export class MarketOperationUtils { getNativeOrderTokens(orders[0])[0], getNativeOrderTokens(orders[0])[1], [makerAmounts[i]], - this._wethAddress, - _opts.tokenAdjacencyGraph, ), ), ]; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts b/packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts new file mode 100644 index 0000000000..e3bda41873 --- /dev/null +++ b/packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts @@ -0,0 +1,12 @@ +import { LiquidityProviderRegistry } from './types'; + +// tslint:disable completed-docs +export function getLiquidityProvidersForPair( + registry: LiquidityProviderRegistry, + takerToken: string, + makerToken: string, +): string[] { + return Object.entries(registry) + .filter(([, tokens]) => [makerToken, takerToken].every(t => tokens.includes(t))) + .map(([providerAddress]) => providerAddress); +} diff --git a/packages/asset-swapper/src/utils/market_operation_utils/multibridge_utils.ts b/packages/asset-swapper/src/utils/market_operation_utils/multibridge_utils.ts deleted file mode 100644 index 86e7f3a755..0000000000 --- a/packages/asset-swapper/src/utils/market_operation_utils/multibridge_utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NULL_ADDRESS, TOKENS } from './constants'; - -// tslint:disable completed-docs - -export function getMultiBridgeIntermediateToken(takerToken: string, makerToken: string): string { - let intermediateToken = NULL_ADDRESS; - if (takerToken !== TOKENS.WETH && makerToken !== TOKENS.WETH) { - intermediateToken = TOKENS.WETH; - } else if (takerToken === TOKENS.USDC || makerToken === TOKENS.USDC) { - intermediateToken = TOKENS.DAI; - } - return intermediateToken; -} diff --git a/packages/asset-swapper/src/utils/market_operation_utils/multihop_utils.ts b/packages/asset-swapper/src/utils/market_operation_utils/multihop_utils.ts index f0a4d2215e..96678b7dd0 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/multihop_utils.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/multihop_utils.ts @@ -21,19 +21,11 @@ export function getIntermediateTokens( makerToken: string, takerToken: string, tokenAdjacencyGraph: TokenAdjacencyGraph, - wethAddress: string, ): string[] { - let intermediateTokens = []; - if (makerToken === wethAddress) { - intermediateTokens = _.get(tokenAdjacencyGraph, takerToken, [] as string[]); - } else if (takerToken === wethAddress) { - intermediateTokens = _.get(tokenAdjacencyGraph, makerToken, [] as string[]); - } else { - intermediateTokens = _.union( - _.intersection(_.get(tokenAdjacencyGraph, takerToken, []), _.get(tokenAdjacencyGraph, makerToken, [])), - [wethAddress], - ); - } + const intermediateTokens = _.intersection( + _.get(tokenAdjacencyGraph, takerToken, tokenAdjacencyGraph.default), + _.get(tokenAdjacencyGraph, makerToken, tokenAdjacencyGraph.default), + ); return _.uniqBy(intermediateTokens, a => a.toLowerCase()).filter( token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(), ); 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 5f09c87c6d..6b8608d58b 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts @@ -15,7 +15,6 @@ import { WALLET_SIGNATURE, ZERO_AMOUNT, } from './constants'; -import { getMultiBridgeIntermediateToken } from './multibridge_utils'; import { AggregationError, BalancerFillData, @@ -28,7 +27,6 @@ import { KyberFillData, LiquidityProviderFillData, MooniswapFillData, - MultiBridgeFillData, MultiHopFillData, NativeCollapsedFill, OptimizedMarketOrder, @@ -193,8 +191,6 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath return opts.contractAddresses.creamBridge; case ERC20BridgeSource.LiquidityProvider: return (fill.fillData as LiquidityProviderFillData).poolAddress; - case ERC20BridgeSource.MultiBridge: - return (fill.fillData as MultiBridgeFillData).poolAddress; case ERC20BridgeSource.MStable: return opts.contractAddresses.mStableBridge; case ERC20BridgeSource.Mooniswap: @@ -301,13 +297,6 @@ export function createBridgeOrder( createSushiSwapBridgeData(sushiSwapFillData.tokenAddressPath, sushiSwapFillData.router), ); break; - case ERC20BridgeSource.MultiBridge: - makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( - makerToken, - bridgeAddress, - createMultiBridgeData(takerToken, makerToken), - ); - break; case ERC20BridgeSource.Kyber: const kyberFillData = (fill as CollapsedFill).fillData!; // tslint:disable-line:no-non-null-assertion makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( @@ -372,15 +361,6 @@ function createBridgeData(tokenAddress: string): string { return encoder.encode({ tokenAddress }); } -function createMultiBridgeData(takerToken: string, makerToken: string): string { - const intermediateToken = getMultiBridgeIntermediateToken(takerToken, makerToken); - const encoder = AbiEncoder.create([ - { name: 'takerToken', type: 'address' }, - { name: 'intermediateToken', type: 'address' }, - ]); - return encoder.encode({ takerToken, intermediateToken }); -} - function createBalancerBridgeData(takerToken: string, poolAddress: string): string { const encoder = AbiEncoder.create([ { name: 'takerToken', type: 'address' }, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/path.ts b/packages/asset-swapper/src/utils/market_operation_utils/path.ts index 8a633753f7..d8f1140dac 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/path.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/path.ts @@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils'; import { MarketOperation } from '../../types'; -import { POSITIVE_INF, SOURCE_FLAGS, ZERO_AMOUNT } from './constants'; +import { POSITIVE_INF, ZERO_AMOUNT } from './constants'; import { createBridgeOrder, createNativeOrder, CreateOrderFromPathOpts, getMakerTakerTokens } from './orders'; import { getCompleteRate, getRate } from './rate_utils'; import { @@ -202,7 +202,7 @@ export class Path { } } } - return doSourcesConflict(this.sourceFlags); + return true; } public isValidNextFill(fill: Fill): boolean { @@ -215,7 +215,7 @@ export class Path { if (fill.parent) { return false; } - return doSourcesConflict(this.sourceFlags | fill.flags); + return true; } private _collapseFills(): ReadonlyArray { @@ -268,9 +268,3 @@ export interface CollapsedPath extends Path { readonly collapsedFills: ReadonlyArray; readonly orders: OptimizedMarketOrder[]; } - -const MULTIBRIDGE_SOURCES = SOURCE_FLAGS.LiquidityProvider | SOURCE_FLAGS.Uniswap; -export function doSourcesConflict(flags: number): boolean { - const multiBridgeConflict = flags & SOURCE_FLAGS.MultiBridge && flags & MULTIBRIDGE_SOURCES; - return !multiBridgeConflict; -} diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts index 5c6f0cc1db..ca06da9de2 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts @@ -8,7 +8,7 @@ import { BalancerPoolsCache } from './balancer_utils'; import { BancorService } from './bancor_service'; import { CreamPoolsCache } from './cream_utils'; import { SamplerOperations } from './sampler_operations'; -import { BatchedOperation } from './types'; +import { BatchedOperation, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types'; /** * Generate sample amounts up to `maxFillAmount`. @@ -40,8 +40,18 @@ export class DexOrderSampler extends SamplerOperations { balancerPoolsCache?: BalancerPoolsCache, creamPoolsCache?: CreamPoolsCache, getBancorServiceFn?: () => BancorService, + tokenAdjacencyGraph?: TokenAdjacencyGraph, + liquidityProviderRegistry?: LiquidityProviderRegistry, ) { - super(_samplerContract, provider, balancerPoolsCache, creamPoolsCache, getBancorServiceFn); + super( + _samplerContract, + provider, + balancerPoolsCache, + creamPoolsCache, + getBancorServiceFn, + tokenAdjacencyGraph, + liquidityProviderRegistry, + ); } /* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */ 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 33b7782893..0927e71ea6 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,17 +1,17 @@ import { SupportedProvider } from '@0x/dev-utils'; import { SignedOrder } from '@0x/types'; -import { BigNumber, NULL_ADDRESS } from '@0x/utils'; +import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import { ERC20BridgeSamplerContract } from '../../wrappers'; import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils'; import { BancorService } from './bancor_service'; -import { MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants'; +import { LIQUIDITY_PROVIDER_REGISTRY, MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, ZERO_AMOUNT } from './constants'; import { CreamPoolsCache } from './cream_utils'; import { getCurveInfosForPair, getSnowSwapInfosForPair, getSwerveInfosForPair } from './curve_utils'; import { getKyberReserveIdsForPair } from './kyber_utils'; -import { getMultiBridgeIntermediateToken } from './multibridge_utils'; +import { getLiquidityProvidersForPair } from './liquidity_provider_utils'; import { getIntermediateTokens } from './multihop_utils'; import { SamplerContractOperation } from './sampler_contract_operation'; import { getShellsForPair } from './shell_utils'; @@ -28,8 +28,8 @@ import { HopInfo, KyberFillData, LiquidityProviderFillData, + LiquidityProviderRegistry, MooniswapFillData, - MultiBridgeFillData, MultiHopFillData, ShellFillData, SnowSwapFillData, @@ -47,7 +47,6 @@ import { */ export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([ ERC20BridgeSource.MultiHop, - ERC20BridgeSource.MultiBridge, ERC20BridgeSource.Native, ]); /** @@ -80,6 +79,8 @@ export class SamplerOperations { public readonly balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(), public readonly creamPoolsCache: CreamPoolsCache = new CreamPoolsCache(), protected readonly getBancorServiceFn?: () => BancorService, // for dependency injection in tests + protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [] }, + public readonly liquidityProviderRegistry: LiquidityProviderRegistry = LIQUIDITY_PROVIDER_REGISTRY, ) {} public async getBancorServiceAsync(): Promise { @@ -221,64 +222,32 @@ export class SamplerOperations { } public getLiquidityProviderSellQuotes( - registryAddress: string, + providerAddress: string, makerToken: string, takerToken: string, takerFillAmounts: BigNumber[], ): SourceQuoteOperation { return new SamplerContractOperation({ source: ERC20BridgeSource.LiquidityProvider, - fillData: {} as LiquidityProviderFillData, // tslint:disable-line:no-object-literal-type-assertion + fillData: { poolAddress: providerAddress }, contract: this._samplerContract, - function: this._samplerContract.sampleSellsFromLiquidityProviderRegistry, - params: [registryAddress, takerToken, makerToken, takerFillAmounts], - callback: (callResults: string, fillData: LiquidityProviderFillData): BigNumber[] => { - const [samples, poolAddress] = this._samplerContract.getABIDecodedReturnData<[BigNumber[], string]>( - 'sampleSellsFromLiquidityProviderRegistry', - callResults, - ); - fillData.poolAddress = poolAddress; - return samples; - }, + function: this._samplerContract.sampleSellsFromLiquidityProvider, + params: [providerAddress, takerToken, makerToken, takerFillAmounts], }); } public getLiquidityProviderBuyQuotes( - registryAddress: string, + providerAddress: string, makerToken: string, takerToken: string, makerFillAmounts: BigNumber[], ): SourceQuoteOperation { return new SamplerContractOperation({ source: ERC20BridgeSource.LiquidityProvider, - fillData: {} as LiquidityProviderFillData, // tslint:disable-line:no-object-literal-type-assertion + fillData: { poolAddress: providerAddress }, contract: this._samplerContract, - function: this._samplerContract.sampleBuysFromLiquidityProviderRegistry, - params: [registryAddress, takerToken, makerToken, makerFillAmounts], - callback: (callResults: string, fillData: LiquidityProviderFillData): BigNumber[] => { - const [samples, poolAddress] = this._samplerContract.getABIDecodedReturnData<[BigNumber[], string]>( - 'sampleBuysFromLiquidityProviderRegistry', - callResults, - ); - fillData.poolAddress = poolAddress; - return samples; - }, - }); - } - - public getMultiBridgeSellQuotes( - multiBridgeAddress: string, - makerToken: string, - intermediateToken: string, - takerToken: string, - takerFillAmounts: BigNumber[], - ): SourceQuoteOperation { - return new SamplerContractOperation({ - source: ERC20BridgeSource.MultiBridge, - fillData: { poolAddress: multiBridgeAddress }, - contract: this._samplerContract, - function: this._samplerContract.sampleSellsFromMultiBridge, - params: [multiBridgeAddress, takerToken, intermediateToken, makerToken, takerFillAmounts], + function: this._samplerContract.sampleBuysFromLiquidityProvider, + params: [providerAddress, takerToken, makerToken, makerFillAmounts], }); } @@ -669,34 +638,15 @@ export class SamplerOperations { makerToken: string, takerToken: string, sellAmount: BigNumber, - wethAddress: string, - tokenAdjacencyGraph: TokenAdjacencyGraph, - liquidityProviderRegistryAddress?: string, ): BatchedOperation>> { const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources); if (_sources.length === 0) { return SamplerOperations.constant([]); } - const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress); + const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph); const subOps = intermediateTokens.map(intermediateToken => { - const firstHopOps = this._getSellQuoteOperations( - _sources, - intermediateToken, - takerToken, - [ZERO_AMOUNT], - wethAddress, - tokenAdjacencyGraph, - liquidityProviderRegistryAddress, - ); - const secondHopOps = this._getSellQuoteOperations( - _sources, - makerToken, - intermediateToken, - [ZERO_AMOUNT], - wethAddress, - tokenAdjacencyGraph, - liquidityProviderRegistryAddress, - ); + const firstHopOps = this._getSellQuoteOperations(_sources, intermediateToken, takerToken, [ZERO_AMOUNT]); + const secondHopOps = this._getSellQuoteOperations(_sources, makerToken, intermediateToken, [ZERO_AMOUNT]); return new SamplerContractOperation({ contract: this._samplerContract, source: ERC20BridgeSource.MultiHop, @@ -747,34 +697,19 @@ export class SamplerOperations { makerToken: string, takerToken: string, buyAmount: BigNumber, - wethAddress: string, - tokenAdjacencyGraph: TokenAdjacencyGraph, - liquidityProviderRegistryAddress?: string, ): BatchedOperation>> { const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources); if (_sources.length === 0) { return SamplerOperations.constant([]); } - const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress); + const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph); const subOps = intermediateTokens.map(intermediateToken => { - const firstHopOps = this._getBuyQuoteOperations( - _sources, - intermediateToken, - takerToken, - [new BigNumber(0)], - wethAddress, - tokenAdjacencyGraph, // TODO is this a bad idea? - liquidityProviderRegistryAddress, - ); - const secondHopOps = this._getBuyQuoteOperations( - _sources, - makerToken, - intermediateToken, - [new BigNumber(0)], - wethAddress, - tokenAdjacencyGraph, - liquidityProviderRegistryAddress, - ); + const firstHopOps = this._getBuyQuoteOperations(_sources, intermediateToken, takerToken, [ + new BigNumber(0), + ]); + const secondHopOps = this._getBuyQuoteOperations(_sources, makerToken, intermediateToken, [ + new BigNumber(0), + ]); return new SamplerContractOperation({ contract: this._samplerContract, source: ERC20BridgeSource.MultiHop, @@ -853,17 +788,10 @@ export class SamplerOperations { ): SourceQuoteOperation { return new SamplerContractOperation({ source: ERC20BridgeSource.Shell, + fillData: { poolAddress }, contract: this._samplerContract, function: this._samplerContract.sampleSellsFromShell, params: [poolAddress, takerToken, makerToken, takerFillAmounts], - callback: (callResults: string, fillData: ShellFillData): BigNumber[] => { - const samples = this._samplerContract.getABIDecodedReturnData( - 'sampleSellsFromShell', - callResults, - ); - fillData.poolAddress = poolAddress; - return samples; - }, }); } @@ -875,17 +803,10 @@ export class SamplerOperations { ): SourceQuoteOperation { return new SamplerContractOperation({ source: ERC20BridgeSource.Shell, + fillData: { poolAddress }, contract: this._samplerContract, function: this._samplerContract.sampleBuysFromShell, params: [poolAddress, takerToken, makerToken, makerFillAmounts], - callback: (callResults: string, fillData: ShellFillData): BigNumber[] => { - const samples = this._samplerContract.getABIDecodedReturnData( - 'sampleBuysFromShell', - callResults, - ); - fillData.poolAddress = poolAddress; - return samples; - }, }); } @@ -936,52 +857,36 @@ export class SamplerOperations { makerToken: string, takerToken: string, takerFillAmount: BigNumber, - liquidityProviderRegistryAddress?: string, - multiBridgeAddress?: string, ): BatchedOperation { if (makerToken.toLowerCase() === takerToken.toLowerCase()) { return SamplerOperations.constant(new BigNumber(1)); } - const getSellQuotes = this.getSellQuotes( - sources, - makerToken, - takerToken, - [takerFillAmount], - NULL_ADDRESS, // weth address - {}, // token adjacency - liquidityProviderRegistryAddress, - multiBridgeAddress, - ); + const subOps = this._getSellQuoteOperations(sources, makerToken, takerToken, [takerFillAmount], { + default: [], + }); return { encodeCall: () => { - const encodedCall = getSellQuotes.encodeCall(); - // All soures were excluded - if (encodedCall === NULL_BYTES) { - return NULL_BYTES; - } - return this._samplerContract.batchCall([encodedCall]).getABIEncodedTransactionData(); + const subCalls = subOps.map(op => op.encodeCall()); + return this._samplerContract.batchCall(subCalls).getABIEncodedTransactionData(); }, handleCallResults: callResults => { - if (callResults === NULL_BYTES) { - return ZERO_AMOUNT; - } const rawSubCallResults = this._samplerContract.getABIDecodedReturnData( 'batchCall', callResults, ); - const samples = getSellQuotes.handleCallResults(rawSubCallResults[0]); + const samples = subOps.map((op, i) => op.handleCallResults(rawSubCallResults[i])); if (samples.length === 0) { return ZERO_AMOUNT; } const flatSortedSamples = samples .reduce((acc, v) => acc.concat(...v)) - .filter(v => !v.output.isZero()) - .sort((a, b) => a.output.comparedTo(b.output)); + .filter(v => !v.isZero()) + .sort((a, b) => a.comparedTo(b)); if (flatSortedSamples.length === 0) { return ZERO_AMOUNT; } const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)]; - return medianSample.output.div(medianSample.input); + return medianSample.div(takerFillAmount); }, }; } @@ -991,21 +896,8 @@ export class SamplerOperations { makerToken: string, takerToken: string, takerFillAmounts: BigNumber[], - wethAddress: string, - tokenAdjacencyGraph: TokenAdjacencyGraph, - liquidityProviderRegistryAddress?: string, - multiBridgeAddress?: string, ): BatchedOperation { - const subOps = this._getSellQuoteOperations( - sources, - makerToken, - takerToken, - takerFillAmounts, - wethAddress, - tokenAdjacencyGraph, - liquidityProviderRegistryAddress, - multiBridgeAddress, - ); + const subOps = this._getSellQuoteOperations(sources, makerToken, takerToken, takerFillAmounts); return { encodeCall: () => { const subCalls = subOps.map(op => op.encodeCall()); @@ -1034,19 +926,8 @@ export class SamplerOperations { makerToken: string, takerToken: string, makerFillAmounts: BigNumber[], - wethAddress: string, - tokenAdjacencyGraph: TokenAdjacencyGraph, - liquidityProviderRegistryAddress?: string, ): BatchedOperation { - const subOps = this._getBuyQuoteOperations( - sources, - makerToken, - takerToken, - makerFillAmounts, - wethAddress, - tokenAdjacencyGraph, - liquidityProviderRegistryAddress, - ); + const subOps = this._getBuyQuoteOperations(sources, makerToken, takerToken, makerFillAmounts); return { encodeCall: () => { const subCalls = subOps.map(op => op.encodeCall()); @@ -1075,21 +956,12 @@ export class SamplerOperations { makerToken: string, takerToken: string, takerFillAmounts: BigNumber[], - wethAddress: string, - tokenAdjacencyGraph: TokenAdjacencyGraph, - liquidityProviderRegistryAddress?: string, - multiBridgeAddress?: string, + tokenAdjacencyGraph: TokenAdjacencyGraph = this.tokenAdjacencyGraph, ): SourceQuoteOperation[] { - const _sources = BATCH_SOURCE_FILTERS.exclude( - liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider], - ) - .exclude(multiBridgeAddress || multiBridgeAddress === NULL_ADDRESS ? [] : [ERC20BridgeSource.MultiBridge]) - .getAllowed(sources); - // Find the adjacent tokens in the provided tooken adjacency graph, // e.g if this is DAI->USDC we may check for DAI->WETH->USDC - const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress); - + const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph); + const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources); return _.flatten( _sources.map( (source): SourceQuoteOperation | SourceQuoteOperation[] => { @@ -1144,30 +1016,12 @@ export class SamplerOperations { ), ); case ERC20BridgeSource.LiquidityProvider: - if (liquidityProviderRegistryAddress === undefined) { - throw new Error( - 'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.', - ); - } - return this.getLiquidityProviderSellQuotes( - liquidityProviderRegistryAddress, - makerToken, + return getLiquidityProvidersForPair( + this.liquidityProviderRegistry, takerToken, - takerFillAmounts, - ); - case ERC20BridgeSource.MultiBridge: - if (multiBridgeAddress === undefined) { - throw new Error( - 'Cannot sample liquidity from MultiBridge if an address is not provided.', - ); - } - const intermediateToken = getMultiBridgeIntermediateToken(takerToken, makerToken); - return this.getMultiBridgeSellQuotes( - multiBridgeAddress, makerToken, - intermediateToken, - takerToken, - takerFillAmounts, + ).map(pool => + this.getLiquidityProviderSellQuotes(pool, makerToken, takerToken, takerFillAmounts), ); case ERC20BridgeSource.MStable: return this.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts); @@ -1216,18 +1070,11 @@ export class SamplerOperations { makerToken: string, takerToken: string, makerFillAmounts: BigNumber[], - wethAddress: string, - tokenAdjacencyGraph: TokenAdjacencyGraph, - liquidityProviderRegistryAddress?: string, ): SourceQuoteOperation[] { - const _sources = BATCH_SOURCE_FILTERS.exclude( - liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider], - ).getAllowed(sources); - // Find the adjacent tokens in the provided tooken adjacency graph, // e.g if this is DAI->USDC we may check for DAI->WETH->USDC - const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress); - + const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph); + const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources); return _.flatten( _sources.map( (source): SourceQuoteOperation | SourceQuoteOperation[] => { @@ -1282,16 +1129,12 @@ export class SamplerOperations { ), ); case ERC20BridgeSource.LiquidityProvider: - if (liquidityProviderRegistryAddress === undefined) { - throw new Error( - 'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.', - ); - } - return this.getLiquidityProviderBuyQuotes( - liquidityProviderRegistryAddress, - makerToken, + return getLiquidityProvidersForPair( + this.liquidityProviderRegistry, takerToken, - makerFillAmounts, + makerToken, + ).map(pool => + this.getLiquidityProviderBuyQuotes(pool, makerToken, takerToken, makerFillAmounts), ); case ERC20BridgeSource.MStable: return this.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts); diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index b5c9bd2abb..fcac2a63fa 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -132,10 +132,6 @@ export interface LiquidityProviderFillData extends FillData { poolAddress: string; } -export interface MultiBridgeFillData extends FillData { - poolAddress: string; -} - export interface BancorFillData extends FillData { path: string[]; networkAddress: string; @@ -375,6 +371,11 @@ export interface MarketSideLiquidity { export interface TokenAdjacencyGraph { [token: string]: string[]; + default: string[]; +} + +export interface LiquidityProviderRegistry { + [address: string]: [string, string]; } export interface GenerateOptimizedOrdersOpts { diff --git a/packages/asset-swapper/src/wrappers.ts b/packages/asset-swapper/src/wrappers.ts index 9e18a8fe91..3ae69ad238 100644 --- a/packages/asset-swapper/src/wrappers.ts +++ b/packages/asset-swapper/src/wrappers.ts @@ -3,8 +3,4 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ -export * from '../generated-wrappers/dummy_liquidity_provider'; -export * from '../generated-wrappers/dummy_liquidity_provider_registry'; export * from '../generated-wrappers/erc20_bridge_sampler'; -export * from '../generated-wrappers/i_liquidity_provider'; -export * from '../generated-wrappers/i_liquidity_provider_registry'; diff --git a/packages/asset-swapper/test/artifacts.ts b/packages/asset-swapper/test/artifacts.ts index 02f8ed1ff6..fd5ae276e0 100644 --- a/packages/asset-swapper/test/artifacts.ts +++ b/packages/asset-swapper/test/artifacts.ts @@ -11,15 +11,12 @@ 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'; import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json'; import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json'; import * as IBalancer from '../test/generated-artifacts/IBalancer.json'; import * as ICurve from '../test/generated-artifacts/ICurve.json'; import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json'; -import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json'; -import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json'; import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json'; import * as IMStable from '../test/generated-artifacts/IMStable.json'; import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json'; @@ -64,8 +61,6 @@ export const artifacts = { ICurve: ICurve as ContractArtifact, IEth2Dai: IEth2Dai as ContractArtifact, IKyberNetwork: IKyberNetwork as ContractArtifact, - ILiquidityProvider: ILiquidityProvider as ContractArtifact, - ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact, IMStable: IMStable as ContractArtifact, IMooniswap: IMooniswap as ContractArtifact, IMultiBridge: IMultiBridge as ContractArtifact, @@ -73,7 +68,6 @@ export const artifacts = { IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact, IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact, DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact, - DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact, TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact, TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact, }; diff --git a/packages/asset-swapper/test/contracts/erc20_bridge_sampler_test.ts b/packages/asset-swapper/test/contracts/erc20_bridge_sampler_test.ts index ce167bcf1c..bbeb46bad9 100644 --- a/packages/asset-swapper/test/contracts/erc20_bridge_sampler_test.ts +++ b/packages/asset-swapper/test/contracts/erc20_bridge_sampler_test.ts @@ -11,11 +11,7 @@ import { BigNumber, hexUtils } from '@0x/utils'; import * as _ from 'lodash'; import { artifacts } from '../artifacts'; -import { - DummyLiquidityProviderContract, - DummyLiquidityProviderRegistryContract, - TestERC20BridgeSamplerContract, -} from '../wrappers'; +import { DummyLiquidityProviderContract, TestERC20BridgeSamplerContract } from '../wrappers'; // tslint:disable: custom-no-magic-numbers @@ -817,7 +813,6 @@ blockchainTests('erc20-bridge-sampler', env => { const yAsset = randomAddress(); const sampleAmounts = getSampleAmounts(yAsset); let liquidityProvider: DummyLiquidityProviderContract; - let registryContract: DummyLiquidityProviderRegistryContract; before(async () => { liquidityProvider = await DummyLiquidityProviderContract.deployFrom0xArtifactAsync( @@ -826,61 +821,33 @@ blockchainTests('erc20-bridge-sampler', env => { env.txDefaults, {}, ); - - registryContract = await DummyLiquidityProviderRegistryContract.deployFrom0xArtifactAsync( - artifacts.DummyLiquidityProviderRegistry, - env.provider, - env.txDefaults, - {}, - ); - await registryContract - .setLiquidityProviderForMarket(xAsset, yAsset, liquidityProvider.address) - .awaitTransactionSuccessAsync(); }); it('should be able to query sells from the liquidity provider', async () => { - const [quotes, providerAddress] = await testContract - .sampleSellsFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts) + const quotes = await testContract + .sampleSellsFromLiquidityProvider(liquidityProvider.address, yAsset, xAsset, sampleAmounts) .callAsync(); quotes.forEach((value, idx) => { expect(value).is.bignumber.eql(sampleAmounts[idx].minus(1)); }); - expect(providerAddress).to.equal(liquidityProvider.address); }); it('should be able to query buys from the liquidity provider', async () => { - const [quotes, providerAddress] = await testContract - .sampleBuysFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts) + const quotes = await testContract + .sampleBuysFromLiquidityProvider(liquidityProvider.address, yAsset, xAsset, sampleAmounts) .callAsync(); quotes.forEach((value, idx) => { expect(value).is.bignumber.eql(sampleAmounts[idx].plus(1)); }); - expect(providerAddress).to.equal(liquidityProvider.address); }); - it('should just return zeros if the liquidity provider cannot be found', async () => { - const [quotes, providerAddress] = await testContract - .sampleBuysFromLiquidityProviderRegistry( - registryContract.address, - yAsset, - randomAddress(), - sampleAmounts, - ) + it('should just return zeros if the liquidity provider does not exist', async () => { + const quotes = await testContract + .sampleBuysFromLiquidityProvider(randomAddress(), yAsset, xAsset, sampleAmounts) .callAsync(); quotes.forEach(value => { expect(value).is.bignumber.eql(constants.ZERO_AMOUNT); }); - expect(providerAddress).to.equal(constants.NULL_ADDRESS); - }); - - it('should just return zeros if the registry does not exist', async () => { - const [quotes, providerAddress] = await testContract - .sampleBuysFromLiquidityProviderRegistry(randomAddress(), yAsset, xAsset, sampleAmounts) - .callAsync(); - quotes.forEach(value => { - expect(value).is.bignumber.eql(constants.ZERO_AMOUNT); - }); - expect(providerAddress).to.equal(constants.NULL_ADDRESS); }); }); diff --git a/packages/asset-swapper/test/dex_sampler_test.ts b/packages/asset-swapper/test/dex_sampler_test.ts index b79bc75475..6a18b562ea 100644 --- a/packages/asset-swapper/test/dex_sampler_test.ts +++ b/packages/asset-swapper/test/dex_sampler_test.ts @@ -36,7 +36,7 @@ describe('DexSampler tests', () => { const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken; const exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange; - const tokenAdjacencyGraph: TokenAdjacencyGraph = {}; + const tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [wethAddress] }; describe('getSampleAmounts()', () => { const FILL_AMOUNT = getRandomInteger(1, 1e18); @@ -159,26 +159,31 @@ describe('DexSampler tests', () => { it('getLiquidityProviderSellQuotes()', async () => { const expectedMakerToken = randomAddress(); const expectedTakerToken = randomAddress(); - const registry = randomAddress(); const poolAddress = randomAddress(); const sampler = new MockSamplerContract({ - sampleSellsFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, _fillAmounts) => { - expect(registryAddress).to.eq(registry); + sampleSellsFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => { + expect(providerAddress).to.eq(poolAddress); expect(takerToken).to.eq(expectedTakerToken); expect(makerToken).to.eq(expectedMakerToken); - return [[toBaseUnitAmount(1001)], poolAddress]; + return [toBaseUnitAmount(1001)]; }, }); - const dexOrderSampler = new DexOrderSampler(sampler); + const dexOrderSampler = new DexOrderSampler( + sampler, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + { [poolAddress]: [expectedMakerToken, expectedTakerToken] }, + ); const [result] = await dexOrderSampler.executeAsync( dexOrderSampler.getSellQuotes( [ERC20BridgeSource.LiquidityProvider], expectedMakerToken, expectedTakerToken, [toBaseUnitAmount(1000)], - wethAddress, - tokenAdjacencyGraph, - registry, ), ); expect(result).to.deep.equal([ @@ -196,26 +201,31 @@ describe('DexSampler tests', () => { it('getLiquidityProviderBuyQuotes()', async () => { const expectedMakerToken = randomAddress(); const expectedTakerToken = randomAddress(); - const registry = randomAddress(); const poolAddress = randomAddress(); const sampler = new MockSamplerContract({ - sampleBuysFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, _fillAmounts) => { - expect(registryAddress).to.eq(registry); + sampleBuysFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => { + expect(providerAddress).to.eq(poolAddress); expect(takerToken).to.eq(expectedTakerToken); expect(makerToken).to.eq(expectedMakerToken); - return [[toBaseUnitAmount(999)], poolAddress]; + return [toBaseUnitAmount(999)]; }, }); - const dexOrderSampler = new DexOrderSampler(sampler); + const dexOrderSampler = new DexOrderSampler( + sampler, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + { [poolAddress]: [expectedMakerToken, expectedTakerToken] }, + ); const [result] = await dexOrderSampler.executeAsync( dexOrderSampler.getBuyQuotes( [ERC20BridgeSource.LiquidityProvider], expectedMakerToken, expectedTakerToken, [toBaseUnitAmount(1000)], - wethAddress, - tokenAdjacencyGraph, - registry, ), ); expect(result).to.deep.equal([ @@ -230,50 +240,6 @@ describe('DexSampler tests', () => { ]); }); - it('getMultiBridgeSellQuotes()', async () => { - const expectedTakerToken = randomAddress(); - const expectedMakerToken = randomAddress(); - const multiBridge = randomAddress(); - - const sampler = new MockSamplerContract({ - sampleSellsFromMultiBridge: ( - multiBridgeAddress, - takerToken, - _intermediateToken, - makerToken, - _fillAmounts, - ) => { - expect(multiBridgeAddress).to.eq(multiBridge); - expect(takerToken).to.eq(expectedTakerToken); - expect(makerToken).to.eq(expectedMakerToken); - return [toBaseUnitAmount(1001)]; - }, - }); - const dexOrderSampler = new DexOrderSampler(sampler); - const [result] = await dexOrderSampler.executeAsync( - dexOrderSampler.getSellQuotes( - [ERC20BridgeSource.MultiBridge], - expectedMakerToken, - expectedTakerToken, - [toBaseUnitAmount(1000)], - wethAddress, - tokenAdjacencyGraph, - randomAddress(), - multiBridge, - ), - ); - expect(result).to.deep.equal([ - [ - { - source: 'MultiBridge', - output: toBaseUnitAmount(1001), - input: toBaseUnitAmount(1000), - fillData: { poolAddress: multiBridge }, - }, - ], - ]); - }); - it('getEth2DaiSellQuotes()', async () => { const expectedTakerToken = randomAddress(); const expectedMakerToken = randomAddress(); @@ -416,15 +382,21 @@ describe('DexSampler tests', () => { return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue()); }, }); - const dexOrderSampler = new DexOrderSampler(sampler); + const dexOrderSampler = new DexOrderSampler( + sampler, + undefined, + undefined, + undefined, + undefined, + undefined, + tokenAdjacencyGraph, + ); const [quotes] = await dexOrderSampler.executeAsync( dexOrderSampler.getSellQuotes( sources, expectedMakerToken, expectedTakerToken, expectedTakerFillAmounts, - wethAddress, - tokenAdjacencyGraph, ), ); const expectedQuotes = sources.map(s => @@ -561,16 +533,17 @@ describe('DexSampler tests', () => { return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue()); }, }); - const dexOrderSampler = new DexOrderSampler(sampler); + const dexOrderSampler = new DexOrderSampler( + sampler, + undefined, + undefined, + undefined, + undefined, + undefined, + tokenAdjacencyGraph, + ); const [quotes] = await dexOrderSampler.executeAsync( - dexOrderSampler.getBuyQuotes( - sources, - expectedMakerToken, - expectedTakerToken, - expectedMakerFillAmounts, - wethAddress, - tokenAdjacencyGraph, - ), + dexOrderSampler.getBuyQuotes(sources, expectedMakerToken, expectedTakerToken, expectedMakerFillAmounts), ); const expectedQuotes = sources.map(s => expectedMakerFillAmounts.map(a => ({ diff --git a/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts b/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts index 924d7782ce..552cde57d0 100644 --- a/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts +++ b/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts @@ -20,7 +20,7 @@ import { constants } from '../src/constants'; import { ExchangeProxySwapQuoteConsumer } from '../src/quote_consumers/exchange_proxy_swap_quote_consumer'; import { getSwapMinBuyAmount } from '../src/quote_consumers/utils'; import { MarketBuySwapQuote, MarketOperation, MarketSellSwapQuote } from '../src/types'; -import { OptimizedMarketOrder } from '../src/utils/market_operation_utils/types'; +import { ERC20BridgeSource, OptimizedMarketOrder } from '../src/utils/market_operation_utils/types'; import { chaiSetup } from './utils/chai_setup'; @@ -161,7 +161,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { ); } - const callDataEncoder = AbiEncoder.createMethod('transformERC20', [ + const transformERC20Encoder = AbiEncoder.createMethod('transformERC20', [ { type: 'address', name: 'inputToken' }, { type: 'address', name: 'outputToken' }, { type: 'uint256', name: 'inputTokenAmount' }, @@ -173,7 +173,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { }, ]); - interface CallArgs { + interface TransformERC20Args { inputToken: string; outputToken: string; inputTokenAmount: BigNumber; @@ -184,11 +184,31 @@ describe('ExchangeProxySwapQuoteConsumer', () => { }>; } + const liquidityProviderEncoder = AbiEncoder.createMethod('sellToLiquidityProvider', [ + { type: 'address', name: 'inputToken' }, + { type: 'address', name: 'outputToken' }, + { type: 'address', name: 'target' }, + { type: 'address', name: 'recipient' }, + { type: 'uint256', name: 'sellAmount' }, + { type: 'uint256', name: 'minBuyAmount' }, + { type: 'bytes', name: 'auxiliaryData' }, + ]); + + interface LiquidityProviderArgs { + inputToken: string; + outputToken: string; + target: string; + recipient: string; + sellAmount: BigNumber; + minBuyAmount: BigNumber; + auxiliaryData: string; + } + describe('getCalldataOrThrow()', () => { it('can produce a sell quote', async () => { const quote = getRandomSellQuote(); const callInfo = await consumer.getCalldataOrThrowAsync(quote); - const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs; + const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args; expect(callArgs.inputToken).to.eq(TAKER_TOKEN); expect(callArgs.outputToken).to.eq(MAKER_TOKEN); expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount); @@ -217,7 +237,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { it('can produce a buy quote', async () => { const quote = getRandomBuyQuote(); const callInfo = await consumer.getCalldataOrThrowAsync(quote); - const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs; + const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args; expect(callArgs.inputToken).to.eq(TAKER_TOKEN); expect(callArgs.outputToken).to.eq(MAKER_TOKEN); expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount); @@ -246,7 +266,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { it('ERC20 -> ERC20 does not have a WETH transformer', async () => { const quote = getRandomSellQuote(); const callInfo = await consumer.getCalldataOrThrowAsync(quote); - const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs; + const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args; const nonces = callArgs.transformations.map(t => t.deploymentNonce); expect(nonces).to.not.include(consumer.transformerNonces.wethTransformer); }); @@ -256,7 +276,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { const callInfo = await consumer.getCalldataOrThrowAsync(quote, { extensionContractOpts: { isFromETH: true }, }); - const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs; + const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args; expect(callArgs.transformations[0].deploymentNonce.toNumber()).to.eq( consumer.transformerNonces.wethTransformer, ); @@ -270,7 +290,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { const callInfo = await consumer.getCalldataOrThrowAsync(quote, { extensionContractOpts: { isToETH: true }, }); - const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs; + const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args; expect(callArgs.transformations[1].deploymentNonce.toNumber()).to.eq( consumer.transformerNonces.wethTransformer, ); @@ -278,7 +298,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { expect(wethTransformerData.amount).to.bignumber.eq(MAX_UINT256); expect(wethTransformerData.token).to.eq(contractAddresses.etherToken); }); - it('Appends an affiliate fee transformer after the fill if a buy token affiliate fee is provided', async () => { + it('Appends an affiliate fee transformer after the fill if a buy token affiliate fee is provided', async () => { const quote = getRandomSellQuote(); const affiliateFee = { recipient: randomAddress(), @@ -288,7 +308,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { const callInfo = await consumer.getCalldataOrThrowAsync(quote, { extensionContractOpts: { affiliateFee }, }); - const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs; + const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args; expect(callArgs.transformations[1].deploymentNonce.toNumber()).to.eq( consumer.transformerNonces.affiliateFeeTransformer, ); @@ -315,7 +335,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { const callInfo = await consumer.getCalldataOrThrowAsync(quote, { extensionContractOpts: { isTwoHop: true }, }); - const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs; + const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args; expect(callArgs.inputToken).to.eq(TAKER_TOKEN); expect(callArgs.outputToken).to.eq(MAKER_TOKEN); expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount); @@ -357,5 +377,35 @@ describe('ExchangeProxySwapQuoteConsumer', () => { INTERMEDIATE_TOKEN, ]); }); + it('Uses the `LiquidityProviderFeature` if given a single LiquidityProvider order', async () => { + const quote = { + ...getRandomSellQuote(), + orders: [ + { + ...getRandomOrder(), + fills: [ + { + source: ERC20BridgeSource.LiquidityProvider, + sourcePathId: '', + input: constants.ZERO_AMOUNT, + output: constants.ZERO_AMOUNT, + subFills: [], + }, + ], + }, + ], + }; + const callInfo = await consumer.getCalldataOrThrowAsync(quote); + const callArgs = liquidityProviderEncoder.decode(callInfo.calldataHexString) as LiquidityProviderArgs; + expect(callArgs).to.deep.equal({ + inputToken: TAKER_TOKEN, + outputToken: MAKER_TOKEN, + target: quote.orders[0].makerAddress, + recipient: constants.NULL_ADDRESS, + sellAmount: quote.worstCaseQuoteInfo.totalTakerAssetAmount, + minBuyAmount: getSwapMinBuyAmount(quote), + auxiliaryData: constants.NULL_BYTES, + }); + }); }); }); diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index a6bfd80bea..a833a3de42 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -11,7 +11,7 @@ import { } from '@0x/contracts-test-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 { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import * as TypeMoq from 'typemoq'; @@ -63,10 +63,11 @@ const DEFAULT_EXCLUDED = [ ERC20BridgeSource.Shell, ERC20BridgeSource.Cream, ERC20BridgeSource.Dodo, + ERC20BridgeSource.LiquidityProvider, ]; const BUY_SOURCES = BUY_SOURCE_FILTER.sources; const SELL_SOURCES = SELL_SOURCE_FILTER.sources; -const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = {}; +const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = { default: [] }; const PRICE_AWARE_RFQ_ENABLED: PriceAwareRFQFlags = { isFirmPriceAwareEnabled: true, isIndicativePriceAwareEnabled: true, @@ -77,7 +78,6 @@ describe('MarketOperationUtils tests', () => { const CHAIN_ID = ChainId.Mainnet; const contractAddresses = { ...getContractAddressesForChainOrThrow(CHAIN_ID), - multiBridge: NULL_ADDRESS, ...BRIDGE_ADDRESSES_BY_CHAIN[CHAIN_ID], }; @@ -242,38 +242,6 @@ describe('MarketOperationUtils tests', () => { }; } - function callTradeOperationAndRetainLiquidityProviderParams( - tradeOperation: (rates: RatesBySource) => GetMultipleQuotesOperation, - rates: RatesBySource, - ): [{ sources: ERC20BridgeSource[]; liquidityProviderAddress?: string }, GetMultipleQuotesOperation] { - const liquidityPoolParams: { sources: ERC20BridgeSource[]; liquidityProviderAddress?: string } = { - sources: [], - liquidityProviderAddress: undefined, - }; - const fn = ( - sources: ERC20BridgeSource[], - makerToken: string, - takerToken: string, - fillAmounts: BigNumber[], - wethAddress: string, - tokenAdjacencyGraph: TokenAdjacencyGraph = TOKEN_ADJACENCY_GRAPH, - liquidityProviderAddress?: string, - ) => { - liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress; - liquidityPoolParams.sources = liquidityPoolParams.sources.concat(sources); - return tradeOperation(rates)( - sources, - makerToken, - takerToken, - fillAmounts, - wethAddress, - TOKEN_ADJACENCY_GRAPH, - liquidityProviderAddress, - ); - }; - return [liquidityPoolParams, fn]; - } - function createGetMultipleBuyQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation { return ( sources: ERC20BridgeSource[], @@ -335,7 +303,6 @@ describe('MarketOperationUtils tests', () => { [ERC20BridgeSource.Bancor]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.Curve]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0), - [ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.Mooniswap]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.Swerve]: _.times(NUM_SAMPLES, () => 0), @@ -480,6 +447,7 @@ describe('MarketOperationUtils tests', () => { }, balancerPoolsCache: new BalancerPoolsCache(), creamPoolsCache: new CreamPoolsCache(), + liquidityProviderRegistry: {}, } as any) as DexOrderSampler; function replaceSamplerOps(ops: Partial = {}): void { @@ -617,54 +585,6 @@ describe('MarketOperationUtils tests', () => { expect(_.uniq(sourcesPolled).sort()).to.deep.equals(SELL_SOURCES.slice().sort()); }); - it('polls the liquidity provider when the registry is provided in the arguments', async () => { - const [args, fn] = callTradeOperationAndRetainLiquidityProviderParams( - createGetMultipleSellQuotesOperationFromRates, - DEFAULT_RATES, - ); - replaceSamplerOps({ - getSellQuotes: fn, - getTwoHopSellQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => { - if (sources.length !== 0) { - args.sources.push(ERC20BridgeSource.MultiHop); - args.sources.push(...sources); - } - return DEFAULT_OPS.getTwoHopSellQuotes(..._args); - }, - getBalancerSellQuotesOffChainAsync: ( - makerToken: string, - takerToken: string, - takerFillAmounts: BigNumber[], - ) => { - args.sources = args.sources.concat(ERC20BridgeSource.Balancer); - return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts); - }, - getCreamSellQuotesOffChainAsync: ( - makerToken: string, - takerToken: string, - takerFillAmounts: BigNumber[], - ) => { - args.sources = args.sources.concat(ERC20BridgeSource.Cream); - return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts); - }, - }); - const registryAddress = randomAddress(); - const newMarketOperationUtils = new MarketOperationUtils( - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - registryAddress, - ); - await newMarketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { - ...DEFAULT_OPTS, - excludedSources: [], - }); - expect(_.uniq(args.sources).sort()).to.deep.equals( - SELL_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(), - ); - expect(args.liquidityProviderAddress).to.eql(registryAddress); - }); - it('does not poll DEXes in `excludedSources`', async () => { const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai]; let sourcesPolled: ERC20BridgeSource[] = []; @@ -1341,41 +1261,28 @@ describe('MarketOperationUtils tests', () => { }); it('is able to create a order from LiquidityProvider', async () => { - const registryAddress = randomAddress(); const liquidityProviderAddress = (DEFAULT_FILL_DATA[ERC20BridgeSource.LiquidityProvider] as any) .poolAddress; - const xAsset = randomAddress(); - const yAsset = randomAddress(); - const toSell = fromTokenUnitAmount(10); - - const [getSellQuotesParams, getSellQuotesFn] = callTradeOperationAndRetainLiquidityProviderParams( - createGetMultipleSellQuotesOperationFromRates, - { - [ERC20BridgeSource.LiquidityProvider]: createDecreasingRates(5), - }, - ); - + const rates: RatesBySource = {}; + rates[ERC20BridgeSource.LiquidityProvider] = [1, 1, 1, 1]; + MOCK_SAMPLER.liquidityProviderRegistry[liquidityProviderAddress] = [MAKER_TOKEN, TAKER_TOKEN]; replaceSamplerOps({ getOrderFillableTakerAmounts: () => [constants.ZERO_AMOUNT], - getSellQuotes: getSellQuotesFn, + getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates), }); - const sampler = new MarketOperationUtils( - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - registryAddress, - ); + const sampler = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN); const ordersAndReport = await sampler.getMarketSellOrdersAsync( [ createOrder({ - makerAssetData: assetDataUtils.encodeERC20AssetData(xAsset), - takerAssetData: assetDataUtils.encodeERC20AssetData(yAsset), + makerAssetData: assetDataUtils.encodeERC20AssetData(MAKER_TOKEN), + takerAssetData: assetDataUtils.encodeERC20AssetData(TAKER_TOKEN), }), ], - Web3Wrapper.toBaseUnitAmount(10, 18), + FILL_AMOUNT, { - excludedSources: SELL_SOURCES.concat(ERC20BridgeSource.Bancor), + includedSources: [ERC20BridgeSource.LiquidityProvider], + excludedSources: [], numSamples: 4, bridgeSlippage: 0, }, @@ -1390,9 +1297,7 @@ describe('MarketOperationUtils tests', () => { ) as ERC20BridgeAssetData; expect(decodedAssetData.assetProxyId).to.eql(AssetProxyId.ERC20Bridge); expect(decodedAssetData.bridgeAddress).to.eql(liquidityProviderAddress); - expect(result[0].takerAssetAmount).to.bignumber.eql(toSell); - expect(getSellQuotesParams.sources).contains(ERC20BridgeSource.LiquidityProvider); - expect(getSellQuotesParams.liquidityProviderAddress).is.eql(registryAddress); + expect(result[0].takerAssetAmount).to.bignumber.eql(FILL_AMOUNT); }); it('factors in exchange proxy gas overhead', async () => { @@ -1403,20 +1308,16 @@ describe('MarketOperationUtils tests', () => { [ERC20BridgeSource.Uniswap]: [1, 1, 1, 1], [ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999], }; + MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN]; replaceSamplerOps({ getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates), getMedianSellRate: createGetMedianSellRate(ETH_TO_MAKER_RATE), }); - const optimizer = new MarketOperationUtils( - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - randomAddress(), // liquidity provider registry - ); + const optimizer = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN); const gasPrice = 100e9; // 100 gwei const exchangeProxyOverhead = (sourceFlags: number) => sourceFlags === SOURCE_FLAGS.LiquidityProvider - ? new BigNumber(3e4).times(gasPrice) + ? constants.ZERO_AMOUNT : new BigNumber(1.3e5).times(gasPrice); const improvedOrdersResponse = await optimizer.getMarketSellOrdersAsync( createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]), @@ -1424,12 +1325,12 @@ describe('MarketOperationUtils tests', () => { { ...DEFAULT_OPTS, numSamples: 4, - excludedSources: [ - ...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]), - ERC20BridgeSource.Eth2Dai, - ERC20BridgeSource.Kyber, - ERC20BridgeSource.Bancor, + includedSources: [ + ERC20BridgeSource.Native, + ERC20BridgeSource.Uniswap, + ERC20BridgeSource.LiquidityProvider, ], + excludedSources: [], exchangeProxyOverhead, }, ); @@ -1529,54 +1430,6 @@ describe('MarketOperationUtils tests', () => { expect(_.uniq(sourcesPolled).sort()).to.deep.equals(BUY_SOURCES.sort()); }); - it('polls the liquidity provider when the registry is provided in the arguments', async () => { - const [args, fn] = callTradeOperationAndRetainLiquidityProviderParams( - createGetMultipleBuyQuotesOperationFromRates, - DEFAULT_RATES, - ); - replaceSamplerOps({ - getBuyQuotes: fn, - getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => { - if (sources.length !== 0) { - args.sources.push(ERC20BridgeSource.MultiHop); - args.sources.push(...sources); - } - return DEFAULT_OPS.getTwoHopBuyQuotes(..._args); - }, - getBalancerBuyQuotesOffChainAsync: ( - makerToken: string, - takerToken: string, - makerFillAmounts: BigNumber[], - ) => { - args.sources = args.sources.concat(ERC20BridgeSource.Balancer); - return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts); - }, - getCreamBuyQuotesOffChainAsync: ( - makerToken: string, - takerToken: string, - makerFillAmounts: BigNumber[], - ) => { - args.sources = args.sources.concat(ERC20BridgeSource.Cream); - return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts); - }, - }); - const registryAddress = randomAddress(); - const newMarketOperationUtils = new MarketOperationUtils( - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - registryAddress, - ); - await newMarketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { - ...DEFAULT_OPTS, - excludedSources: [], - }); - expect(_.uniq(args.sources).sort()).to.deep.eq( - BUY_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(), - ); - expect(args.liquidityProviderAddress).to.eql(registryAddress); - }); - it('does not poll DEXes in `excludedSources`', async () => { const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai]; let sourcesPolled: ERC20BridgeSource[] = []; @@ -1874,20 +1727,16 @@ describe('MarketOperationUtils tests', () => { [ERC20BridgeSource.Uniswap]: [1, 1, 1, 1], [ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999], }; + MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN]; replaceSamplerOps({ getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates), getMedianSellRate: createGetMedianSellRate(ETH_TO_TAKER_RATE), }); - const optimizer = new MarketOperationUtils( - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - randomAddress(), // liquidity provider registry - ); + const optimizer = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN); const gasPrice = 100e9; // 100 gwei const exchangeProxyOverhead = (sourceFlags: number) => sourceFlags === SOURCE_FLAGS.LiquidityProvider - ? new BigNumber(3e4).times(gasPrice) + ? constants.ZERO_AMOUNT : new BigNumber(1.3e5).times(gasPrice); const improvedOrdersResponse = await optimizer.getMarketBuyOrdersAsync( createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]), @@ -1895,11 +1744,12 @@ describe('MarketOperationUtils tests', () => { { ...DEFAULT_OPTS, numSamples: 4, - excludedSources: [ - ...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]), - ERC20BridgeSource.Eth2Dai, - ERC20BridgeSource.Kyber, + includedSources: [ + ERC20BridgeSource.Native, + ERC20BridgeSource.Uniswap, + ERC20BridgeSource.LiquidityProvider, ], + excludedSources: [], exchangeProxyOverhead, }, ); diff --git a/packages/asset-swapper/test/utils/mock_sampler_contract.ts b/packages/asset-swapper/test/utils/mock_sampler_contract.ts index eb261f0b05..007083cb31 100644 --- a/packages/asset-swapper/test/utils/mock_sampler_contract.ts +++ b/packages/asset-swapper/test/utils/mock_sampler_contract.ts @@ -37,19 +37,12 @@ export type SampleBuysKyberHandler = ( ) => [string, SampleResults]; export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults; export type SampleSellsLPHandler = ( - registryAddress: string, + providerAddress: string, takerToken: string, makerToken: string, takerTokenAmounts: BigNumber[], -) => [SampleResults, string]; -export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults; -export type SampleSellsMBHandler = ( - multiBridgeAddress: string, - takerToken: string, - intermediateToken: string, - makerToken: string, - takerTokenAmounts: BigNumber[], ) => SampleResults; +export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults; const DUMMY_PROVIDER = { sendAsync: (..._args: any[]): any => { @@ -61,15 +54,14 @@ interface Handlers { getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler; getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler; sampleSellsFromKyberNetwork: SampleSellsKyberHandler; - sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler; - sampleSellsFromMultiBridge: SampleSellsMBHandler; + sampleSellsFromLiquidityProvider: SampleSellsLPHandler; sampleSellsFromEth2Dai: SampleSellsHandler; sampleSellsFromUniswap: SampleSellsHandler; sampleSellsFromUniswapV2: SampleSellsMultihopHandler; sampleBuysFromEth2Dai: SampleBuysHandler; sampleBuysFromUniswap: SampleBuysHandler; sampleBuysFromUniswapV2: SampleBuysMultihopHandler; - sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler; + sampleBuysFromLiquidityProvider: SampleSellsLPHandler; } // tslint:disable: no-unbound-method @@ -171,35 +163,17 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract { ); } - public sampleSellsFromLiquidityProviderRegistry( - registryAddress: string, + public sampleSellsFromLiquidityProvider( + providerAddress: string, takerToken: string, makerToken: string, takerAssetAmounts: BigNumber[], - ): ContractTxFunctionObj<[BigNumber[], string]> { - return this._wrapCall( - super.sampleSellsFromLiquidityProviderRegistry, - this._handlers.sampleSellsFromLiquidityProviderRegistry, - registryAddress, - takerToken, - makerToken, - takerAssetAmounts, - ); - } - - public sampleSellsFromMultiBridge( - multiBridgeAddress: string, - takerToken: string, - intermediateToken: string, - makerToken: string, - takerAssetAmounts: BigNumber[], ): ContractTxFunctionObj { return this._wrapCall( - super.sampleSellsFromMultiBridge, - this._handlers.sampleSellsFromMultiBridge, - multiBridgeAddress, + super.sampleSellsFromLiquidityProvider, + this._handlers.sampleSellsFromLiquidityProvider, + providerAddress, takerToken, - intermediateToken, makerToken, takerAssetAmounts, ); diff --git a/packages/asset-swapper/test/wrappers.ts b/packages/asset-swapper/test/wrappers.ts index 69c32cad67..9a49445ce8 100644 --- a/packages/asset-swapper/test/wrappers.ts +++ b/packages/asset-swapper/test/wrappers.ts @@ -9,15 +9,12 @@ 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'; export * from '../test/generated-wrappers/eth2_dai_sampler'; export * from '../test/generated-wrappers/i_balancer'; export * from '../test/generated-wrappers/i_curve'; export * from '../test/generated-wrappers/i_eth2_dai'; export * from '../test/generated-wrappers/i_kyber_network'; -export * from '../test/generated-wrappers/i_liquidity_provider'; -export * from '../test/generated-wrappers/i_liquidity_provider_registry'; export * from '../test/generated-wrappers/i_m_stable'; export * from '../test/generated-wrappers/i_mooniswap'; export * from '../test/generated-wrappers/i_multi_bridge'; diff --git a/packages/asset-swapper/tsconfig.json b/packages/asset-swapper/tsconfig.json index d56c814b13..e17ffb37a8 100644 --- a/packages/asset-swapper/tsconfig.json +++ b/packages/asset-swapper/tsconfig.json @@ -3,26 +3,19 @@ "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "files": [ - "generated-artifacts/DummyLiquidityProvider.json", - "generated-artifacts/DummyLiquidityProviderRegistry.json", "generated-artifacts/ERC20BridgeSampler.json", - "generated-artifacts/ILiquidityProvider.json", - "generated-artifacts/ILiquidityProviderRegistry.json", "test/generated-artifacts/ApproximateBuys.json", "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", "test/generated-artifacts/Eth2DaiSampler.json", "test/generated-artifacts/IBalancer.json", "test/generated-artifacts/ICurve.json", "test/generated-artifacts/IEth2Dai.json", "test/generated-artifacts/IKyberNetwork.json", - "test/generated-artifacts/ILiquidityProvider.json", - "test/generated-artifacts/ILiquidityProviderRegistry.json", "test/generated-artifacts/IMStable.json", "test/generated-artifacts/IMooniswap.json", "test/generated-artifacts/IMultiBridge.json", diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index 0986e24059..f0f3de0af1 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "5.3.0", + "changes": [ + { + "note": "Add `exchangeProxyLiquidityProviderSandbox` addresses", + "pr": 16 + } + ] + }, { "version": "5.2.0", "changes": [ diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index 1110ba617e..2dd4fd94f9 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -32,6 +32,7 @@ "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x39dce47a67ad34344eab877eae3ef1fa2a1d50bb", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", + "exchangeProxyLiquidityProviderSandbox": "0xdb971b18ea5075734cec1241732cc1b41031dfc9", "transformers": { "wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e", "payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7", @@ -72,6 +73,7 @@ "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", + "exchangeProxyLiquidityProviderSandbox": "0xb8afda68a9834969a69ebd4aab201feff814d170", "transformers": { "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", @@ -112,6 +114,7 @@ "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", + "exchangeProxyLiquidityProviderSandbox": "0xb8afda68a9834969a69ebd4aab201feff814d170", "transformers": { "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", @@ -152,6 +155,7 @@ "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", "exchangeProxyTransformerDeployer": "0x1b62de2dbb5e7aa519e9c442721ecef75702807f", "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", + "exchangeProxyLiquidityProviderSandbox": "0x598d7a659d1f163d94abe3628674f8a2569ff344", "transformers": { "wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d", "payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977", @@ -192,6 +196,7 @@ "exchangeProxyAllowanceTarget": "0x8362c3ebd90041b30ec45908332e592721642637", "exchangeProxyTransformerDeployer": "0x5409ed021d9299bf6814279a6a1411a7e866a631", "exchangeProxyFlashWallet": "0xb9682a8e7920b431f1d412b8510f0077410c8faa", + "exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000", "transformers": { "wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5", "payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3", diff --git a/packages/contract-addresses/src/index.ts b/packages/contract-addresses/src/index.ts index d140ef8c44..5ce4b0d738 100644 --- a/packages/contract-addresses/src/index.ts +++ b/packages/contract-addresses/src/index.ts @@ -33,6 +33,7 @@ export interface ContractAddresses { exchangeProxyAllowanceTarget: string; exchangeProxyTransformerDeployer: string; exchangeProxyFlashWallet: string; + exchangeProxyLiquidityProviderSandbox: string; transformers: { wethTransformer: string; payTakerTransformer: string; diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json index 3a0e0549cc..60e8ec394b 100644 --- a/packages/contract-artifacts/CHANGELOG.json +++ b/packages/contract-artifacts/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "3.9.0", + "changes": [ + { + "note": "Update IZeroEx artifact and remove some unused artifacts", + "pr": 16 + } + ] + }, { "timestamp": 1604376968, "version": "3.8.2", diff --git a/packages/contract-artifacts/artifacts/DummyLiquidityProvider.json b/packages/contract-artifacts/artifacts/DummyLiquidityProvider.json deleted file mode 100644 index e06cf8a361..0000000000 --- a/packages/contract-artifacts/artifacts/DummyLiquidityProvider.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "schemaVersion": "2.0.0", - "contractName": "DummyLiquidityProvider", - "compilerOutput": { - "abi": [ - { - "constant": true, - "inputs": [ - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "uint256", "name": "buyAmount", "type": "uint256" } - ], - "name": "getBuyQuote", - "outputs": [{ "internalType": "uint256", "name": "takerTokenAmount", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "uint256", "name": "sellAmount", "type": "uint256" } - ], - "name": "getSellQuote", - "outputs": [{ "internalType": "uint256", "name": "makerTokenAmount", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - } - ], - "devdoc": { - "methods": { - "getBuyQuote(address,address,uint256)": { - "details": "Quotes the amount of `takerToken` that would need to be sold in order to obtain `buyAmount` of `makerToken`.", - "params": { "buyAmount": "Amount of `makerToken` to buy." }, - "return": "takerTokenAmount Amount of `takerToken` that would need to be sold." - }, - "getSellQuote(address,address,uint256)": { - "details": "Quotes the amount of `makerToken` that would be obtained by selling `sellAmount` of `takerToken`.", - "params": { "sellAmount": "Amount of `takerToken` to sell." }, - "return": "makerTokenAmount Amount of `makerToken` that would be obtained." - } - } - }, - "evm": { - "bytecode": { - "object": "0x608060405234801561001057600080fd5b50610159806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063343fbcdd1461003b57806345060eb014610064575b600080fd5b61004e6100493660046100a8565b610077565b60405161005b91906100e8565b60405180910390f35b61004e6100723660046100a8565b61009f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b60010192915050565b6000806000606084860312156100bc578283fd5b83356100c7816100f1565b925060208401356100d7816100f1565b929592945050506040919091013590565b90815260200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461011357600080fd5b5056fea365627a7a72315820981135e6e25d9062a0a9bcf7e08e326cde449b18310db7488d1db4e79ef0f6f36c6578706572696d656e74616cf564736f6c63430005100040" - }, - "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063343fbcdd1461003b57806345060eb014610064575b600080fd5b61004e6100493660046100a8565b610077565b60405161005b91906100e8565b60405180910390f35b61004e6100723660046100a8565b61009f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b60010192915050565b6000806000606084860312156100bc578283fd5b83356100c7816100f1565b925060208401356100d7816100f1565b929592945050506040919091013590565b90815260200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461011357600080fd5b5056fea365627a7a72315820981135e6e25d9062a0a9bcf7e08e326cde449b18310db7488d1db4e79ef0f6f36c6578706572696d656e74616cf564736f6c63430005100040" - } - } - }, - "compiler": { - "name": "solc", - "version": "soljson-v0.5.16+commit.9c3226ce.js", - "settings": { - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - }, - "evmVersion": "istanbul" - } - }, - "chains": {} -} diff --git a/packages/contract-artifacts/artifacts/DummyLiquidityProviderRegistry.json b/packages/contract-artifacts/artifacts/DummyLiquidityProviderRegistry.json deleted file mode 100644 index 6d6a0f0baf..0000000000 --- a/packages/contract-artifacts/artifacts/DummyLiquidityProviderRegistry.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "schemaVersion": "2.0.0", - "contractName": "DummyLiquidityProviderRegistry", - "compilerOutput": { - "abi": [ - { - "constant": true, - "inputs": [ - { "internalType": "address", "name": "xToken", "type": "address" }, - { "internalType": "address", "name": "yToken", "type": "address" } - ], - "name": "getLiquidityProviderForMarket", - "outputs": [{ "internalType": "address", "name": "poolAddress", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "address", "name": "xToken", "type": "address" }, - { "internalType": "address", "name": "yToken", "type": "address" }, - { "internalType": "address", "name": "poolAddress", "type": "address" } - ], - "name": "setLiquidityProviderForMarket", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - } - ], - "devdoc": { - "methods": { - "getLiquidityProviderForMarket(address,address)": { - "details": "Returns the address of pool for a market given market (xAsset, yAsset), or reverts if pool does not exist.", - "params": { "xToken": "First asset managed by pool.", "yToken": "Second asset managed by pool." }, - "return": "Address of pool." - }, - "setLiquidityProviderForMarket(address,address,address)": { - "details": "Sets address of pool for a market given market (xAsset, yAsset).", - "params": { - "poolAddress": "Address of pool.", - "xToken": "First asset managed by pool.", - "yToken": "Second asset managed by pool." - } - } - } - }, - "evm": { - "bytecode": { - "object": "0x608060405234801561001057600080fd5b506102a6806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063153f59971461003b57806384da8d1e14610064575b600080fd5b61004e610049366004610192565b610079565b60405161005b919061020b565b60405180910390f35b6100776100723660046101c6565b6100f2565b005b73ffffffffffffffffffffffffffffffffffffffff808316600090815260208181526040808320858516845290915290205416806100ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e39061022c565b60405180910390fd5b92915050565b73ffffffffffffffffffffffffffffffffffffffff92831660008181526020818152604080832095871683529481528482208054969094167fffffffffffffffffffffffff0000000000000000000000000000000000000000968716811790945581815284822092825291909152919091208054909216179055565b803573ffffffffffffffffffffffffffffffffffffffff811681146100ec57600080fd5b600080604083850312156101a4578182fd5b6101ae848461016e565b91506101bd846020850161016e565b90509250929050565b6000806000606084860312156101da578081fd5b6101e4858561016e565b92506101f3856020860161016e565b9150610202856040860161016e565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252601c908201527f52656769737472792f4d41524b45545f504149525f4e4f545f5345540000000060408201526060019056fea365627a7a723158200b589233a17eab806bfb7e334f40bc1ba4502479e55b2aa562c069bc440ceb476c6578706572696d656e74616cf564736f6c63430005100040" - }, - "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063153f59971461003b57806384da8d1e14610064575b600080fd5b61004e610049366004610192565b610079565b60405161005b919061020b565b60405180910390f35b6100776100723660046101c6565b6100f2565b005b73ffffffffffffffffffffffffffffffffffffffff808316600090815260208181526040808320858516845290915290205416806100ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e39061022c565b60405180910390fd5b92915050565b73ffffffffffffffffffffffffffffffffffffffff92831660008181526020818152604080832095871683529481528482208054969094167fffffffffffffffffffffffff0000000000000000000000000000000000000000968716811790945581815284822092825291909152919091208054909216179055565b803573ffffffffffffffffffffffffffffffffffffffff811681146100ec57600080fd5b600080604083850312156101a4578182fd5b6101ae848461016e565b91506101bd846020850161016e565b90509250929050565b6000806000606084860312156101da578081fd5b6101e4858561016e565b92506101f3856020860161016e565b9150610202856040860161016e565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252601c908201527f52656769737472792f4d41524b45545f504149525f4e4f545f5345540000000060408201526060019056fea365627a7a723158200b589233a17eab806bfb7e334f40bc1ba4502479e55b2aa562c069bc440ceb476c6578706572696d656e74616cf564736f6c63430005100040" - } - } - }, - "compiler": { - "name": "solc", - "version": "soljson-v0.5.16+commit.9c3226ce.js", - "settings": { - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - }, - "evmVersion": "istanbul" - } - }, - "chains": {} -} diff --git a/packages/contract-artifacts/artifacts/ILiquidityProviderRegistry.json b/packages/contract-artifacts/artifacts/ILiquidityProviderRegistry.json deleted file mode 100644 index 6264ca0b0d..0000000000 --- a/packages/contract-artifacts/artifacts/ILiquidityProviderRegistry.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "schemaVersion": "2.0.0", - "contractName": "ILiquidityProviderRegistry", - "compilerOutput": { - "abi": [ - { - "constant": true, - "inputs": [ - { "internalType": "address", "name": "takerToken", "type": "address" }, - { "internalType": "address", "name": "makerToken", "type": "address" } - ], - "name": "getLiquidityProviderForMarket", - "outputs": [{ "internalType": "address", "name": "providerAddress", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - } - ], - "devdoc": { - "methods": { - "getLiquidityProviderForMarket(address,address)": { - "details": "Returns the address of a liquidity provider for the given market (takerToken, makerToken), reverting if the pool does not exist.", - "params": { - "makerToken": "Maker asset managed by liquidity provider.", - "takerToken": "Taker asset managed by liquidity provider." - }, - "return": "Address of the liquidity provider." - } - } - }, - "evm": { "bytecode": { "object": "0x" }, "deployedBytecode": { "object": "0x" } } - }, - "compiler": { - "name": "solc", - "version": "soljson-v0.5.16+commit.9c3226ce.js", - "settings": { - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - }, - "evmVersion": "istanbul" - } - }, - "chains": {} -} diff --git a/packages/contract-artifacts/artifacts/IZeroEx.json b/packages/contract-artifacts/artifacts/IZeroEx.json index 96f2b33437..4b4bd1c8a6 100644 --- a/packages/contract-artifacts/artifacts/IZeroEx.json +++ b/packages/contract-artifacts/artifacts/IZeroEx.json @@ -3,16 +3,6 @@ "contractName": "IZeroEx", "compilerOutput": { "abi": [ - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "xAsset", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "yAsset", "type": "address" }, - { "indexed": false, "internalType": "address", "name": "providerAddress", "type": "address" } - ], - "name": "LiquidityProviderForMarketUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -232,16 +222,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { "internalType": "address", "name": "xAsset", "type": "address" }, - { "internalType": "address", "name": "yAsset", "type": "address" } - ], - "name": "getLiquidityProviderForMarket", - "outputs": [{ "internalType": "address", "name": "providerAddress", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -390,9 +370,11 @@ "inputs": [ { "internalType": "address", "name": "makerToken", "type": "address" }, { "internalType": "address", "name": "takerToken", "type": "address" }, - { "internalType": "address payable", "name": "recipient", "type": "address" }, + { "internalType": "address payable", "name": "target", "type": "address" }, + { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } + { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }, + { "internalType": "bytes", "name": "auxiliaryData", "type": "bytes" } ], "name": "sellToLiquidityProvider", "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }], @@ -411,17 +393,6 @@ "stateMutability": "payable", "type": "function" }, - { - "inputs": [ - { "internalType": "address", "name": "xAsset", "type": "address" }, - { "internalType": "address", "name": "yAsset", "type": "address" }, - { "internalType": "address", "name": "providerAddress", "type": "address" } - ], - "name": "setLiquidityProviderForMarket", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [{ "internalType": "address", "name": "quoteSigner", "type": "address" }], "name": "setQuoteSigner", @@ -536,14 +507,6 @@ "params": { "selector": "The function selector." }, "returns": { "impl": "The implementation contract address." } }, - "getLiquidityProviderForMarket(address,address)": { - "details": "Returns the address of the liquidity provider for a market given (xAsset, yAsset), or reverts if pool does not exist.", - "params": { - "xAsset": "First asset managed by the liquidity provider.", - "yAsset": "Second asset managed by the liquidity provider." - }, - "returns": { "providerAddress": "Address of the liquidity provider." } - }, "getMetaTransactionExecutedBlock((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256))": { "details": "Get the block at which a meta-transaction has been executed.", "params": { "mtx": "The meta-transaction." }, @@ -616,6 +579,19 @@ "targetImpl": "The address of an older implementation of the function." } }, + "sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)": { + "details": "Sells `sellAmount` of `takerToken` to the liquidity provider at the given `target`.", + "params": { + "auxiliaryData": "Auxiliary data supplied to the `target` contract.", + "makerToken": "The token being bought.", + "minBuyAmount": "The minimum acceptable amount of `makerToken` to buy. Reverts if this amount is not satisfied.", + "recipient": "The recipient of the bought tokens. If equal to address(0), `msg.sender` is assumed to be the recipient.", + "sellAmount": "The amount of `takerToken` to sell.", + "takerToken": "The token being sold.", + "target": "The address of the on-chain liquidity provider to trade with." + }, + "returns": { "boughtAmount": "The amount of `makerToken` bought." } + }, "sellToUniswap(address[],uint256,uint256,bool)": { "details": "Efficiently sell directly to uniswap/sushiswap.", "params": { @@ -626,14 +602,6 @@ }, "returns": { "buyAmount": "Amount of `tokens[-1]` bought." } }, - "setLiquidityProviderForMarket(address,address,address)": { - "details": "Sets address of the liquidity provider for a market given (xAsset, yAsset).", - "params": { - "providerAddress": "Address of the liquidity provider.", - "xAsset": "First asset managed by the liquidity provider.", - "yAsset": "Second asset managed by the liquidity provider." - } - }, "setQuoteSigner(address)": { "details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.", "params": { "quoteSigner": "The address of the new calldata signer." } diff --git a/packages/contract-artifacts/package.json b/packages/contract-artifacts/package.json index 2897c73de9..3d2a5cea86 100644 --- a/packages/contract-artifacts/package.json +++ b/packages/contract-artifacts/package.json @@ -11,7 +11,7 @@ }, "scripts": { "artifacts_copy": "node lib/src/copy.js", - "artifacts_transform": "node lib/src/transform.js ./artifacts && prettier --write ./artifacts/*.json && cp -r ./artifacts/ ../../python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/", + "artifacts_transform": "node lib/src/transform.js ./artifacts && prettier --write ./artifacts/*.json", "artifacts_update": "yarn artifacts_copy && yarn artifacts_transform && yarn build", "build": "yarn tsc -b", "build:ci": "yarn build", diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index a47457bbc2..fa9984eb57 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "13.10.0", + "changes": [ + { + "note": "Update IZeroEx wrapper and remove ILiquidityProviderRegistry wrapper", + "pr": 16 + } + ] + }, { "timestamp": 1604385937, "version": "13.9.5", diff --git a/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider_registry.ts b/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider_registry.ts deleted file mode 100644 index cad071c486..0000000000 --- a/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider_registry.ts +++ /dev/null @@ -1,327 +0,0 @@ -// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming -// tslint:disable:whitespace no-unbound-method no-trailing-whitespace -// tslint:disable:no-unused-variable -import { - AwaitTransactionSuccessOpts, - ContractFunctionObj, - ContractTxFunctionObj, - SendTransactionOpts, - BaseContract, - PromiseWithTransactionHash, - methodAbiToFunctionSignature, - linkLibrariesInBytecode, -} from '@0x/base-contract'; -import { schemas } from '@0x/json-schemas'; -import { - BlockParam, - BlockParamLiteral, - BlockRange, - CallData, - ContractAbi, - ContractArtifact, - DecodedLogArgs, - MethodAbi, - TransactionReceiptWithDecodedLogs, - TxData, - TxDataPayable, - SupportedProvider, -} from 'ethereum-types'; -import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils'; -import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { assert } from '@0x/assert'; -import * as ethers from 'ethers'; -// tslint:enable:no-unused-variable - -/* istanbul ignore next */ -// tslint:disable:array-type -// tslint:disable:no-parameter-reassignment -// tslint:disable-next-line:class-name -export class ILiquidityProviderRegistryContract extends BaseContract { - /** - * @ignore - */ - public static deployedBytecode: string | undefined; - public static contractName = 'ILiquidityProviderRegistry'; - private readonly _methodABIIndex: { [name: string]: number } = {}; - public static async deployFrom0xArtifactAsync( - artifact: ContractArtifact | SimpleContractArtifact, - supportedProvider: SupportedProvider, - txDefaults: Partial, - logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, - ): Promise { - assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (artifact.compilerOutput === undefined) { - throw new Error('Compiler output not found in the artifact file'); - } - const provider = providerUtils.standardizeOrThrow(supportedProvider); - const bytecode = artifact.compilerOutput.evm.bytecode.object; - const abi = artifact.compilerOutput.abi; - const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; - if (Object.keys(logDecodeDependencies) !== undefined) { - for (const key of Object.keys(logDecodeDependencies)) { - logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; - } - } - return ILiquidityProviderRegistryContract.deployAsync( - bytecode, - abi, - provider, - txDefaults, - logDecodeDependenciesAbiOnly, - ); - } - - public static async deployWithLibrariesFrom0xArtifactAsync( - artifact: ContractArtifact, - libraryArtifacts: { [libraryName: string]: ContractArtifact }, - supportedProvider: SupportedProvider, - txDefaults: Partial, - logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, - ): Promise { - assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (artifact.compilerOutput === undefined) { - throw new Error('Compiler output not found in the artifact file'); - } - const provider = providerUtils.standardizeOrThrow(supportedProvider); - const abi = artifact.compilerOutput.abi; - const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; - if (Object.keys(logDecodeDependencies) !== undefined) { - for (const key of Object.keys(logDecodeDependencies)) { - logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; - } - } - const libraryAddresses = await ILiquidityProviderRegistryContract._deployLibrariesAsync( - artifact, - libraryArtifacts, - new Web3Wrapper(provider), - txDefaults, - ); - const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); - return ILiquidityProviderRegistryContract.deployAsync( - bytecode, - abi, - provider, - txDefaults, - logDecodeDependenciesAbiOnly, - ); - } - - public static async deployAsync( - bytecode: string, - abi: ContractAbi, - supportedProvider: SupportedProvider, - txDefaults: Partial, - logDecodeDependencies: { [contractName: string]: ContractAbi }, - ): Promise { - assert.isHexString('bytecode', bytecode); - assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - const provider = providerUtils.standardizeOrThrow(supportedProvider); - const constructorAbi = BaseContract._lookupConstructorAbi(abi); - [] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString); - const iface = new ethers.utils.Interface(abi); - const deployInfo = iface.deployFunction; - const txData = deployInfo.encode(bytecode, []); - const web3Wrapper = new Web3Wrapper(provider); - const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( - { - data: txData, - ...txDefaults, - }, - web3Wrapper.estimateGasAsync.bind(web3Wrapper), - ); - const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); - logUtils.log(`transactionHash: ${txHash}`); - const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); - logUtils.log(`ILiquidityProviderRegistry successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ILiquidityProviderRegistryContract( - txReceipt.contractAddress as string, - provider, - txDefaults, - logDecodeDependencies, - ); - contractInstance.constructorArgs = []; - return contractInstance; - } - - /** - * @returns The contract ABI - */ - public static ABI(): ContractAbi { - const abi = [ - { - constant: true, - inputs: [ - { - name: 'takerToken', - type: 'address', - }, - { - name: 'makerToken', - type: 'address', - }, - ], - name: 'getLiquidityProviderForMarket', - outputs: [ - { - name: 'providerAddress', - type: 'address', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - ] as ContractAbi; - return abi; - } - - protected static async _deployLibrariesAsync( - artifact: ContractArtifact, - libraryArtifacts: { [libraryName: string]: ContractArtifact }, - web3Wrapper: Web3Wrapper, - txDefaults: Partial, - libraryAddresses: { [libraryName: string]: string } = {}, - ): Promise<{ [libraryName: string]: string }> { - const links = artifact.compilerOutput.evm.bytecode.linkReferences; - // Go through all linked libraries, recursively deploying them if necessary. - for (const link of Object.values(links)) { - for (const libraryName of Object.keys(link)) { - if (!libraryAddresses[libraryName]) { - // Library not yet deployed. - const libraryArtifact = libraryArtifacts[libraryName]; - if (!libraryArtifact) { - throw new Error(`Missing artifact for linked library "${libraryName}"`); - } - // Deploy any dependent libraries used by this library. - await ILiquidityProviderRegistryContract._deployLibrariesAsync( - libraryArtifact, - libraryArtifacts, - web3Wrapper, - txDefaults, - libraryAddresses, - ); - // Deploy this library. - const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); - const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( - { - data: linkedLibraryBytecode, - ...txDefaults, - }, - web3Wrapper.estimateGasAsync.bind(web3Wrapper), - ); - const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); - logUtils.log(`transactionHash: ${txHash}`); - const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash); - logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`); - libraryAddresses[libraryArtifact.contractName] = contractAddress as string; - } - } - } - return libraryAddresses; - } - - public getFunctionSignature(methodName: string): string { - const index = this._methodABIIndex[methodName]; - const methodAbi = ILiquidityProviderRegistryContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion - const functionSignature = methodAbiToFunctionSignature(methodAbi); - return functionSignature; - } - - public getABIDecodedTransactionData(methodName: string, callData: string): T { - const functionSignature = this.getFunctionSignature(methodName); - const self = (this as any) as ILiquidityProviderRegistryContract; - const abiEncoder = self._lookupAbiEncoder(functionSignature); - const abiDecodedCallData = abiEncoder.strictDecode(callData); - return abiDecodedCallData; - } - - public getABIDecodedReturnData(methodName: string, callData: string): T { - const functionSignature = this.getFunctionSignature(methodName); - const self = (this as any) as ILiquidityProviderRegistryContract; - const abiEncoder = self._lookupAbiEncoder(functionSignature); - const abiDecodedCallData = abiEncoder.strictDecodeReturnValue(callData); - return abiDecodedCallData; - } - - public getSelector(methodName: string): string { - const functionSignature = this.getFunctionSignature(methodName); - const self = (this as any) as ILiquidityProviderRegistryContract; - const abiEncoder = self._lookupAbiEncoder(functionSignature); - return abiEncoder.getSelector(); - } - - /** - * Returns the address of a liquidity provider for the given market - * (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. - * @returns Address of the liquidity provider. - */ - public getLiquidityProviderForMarket(takerToken: string, makerToken: string): ContractFunctionObj { - const self = (this as any) as ILiquidityProviderRegistryContract; - assert.isString('takerToken', takerToken); - assert.isString('makerToken', makerToken); - const functionSignature = 'getLiquidityProviderForMarket(address,address)'; - - return { - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { data: this.getABIEncodedTransactionData(), ...callData }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - takerToken.toLowerCase(), - makerToken.toLowerCase(), - ]); - }, - }; - } - - constructor( - address: string, - supportedProvider: SupportedProvider, - txDefaults?: Partial, - logDecodeDependencies?: { [contractName: string]: ContractAbi }, - deployedBytecode: string | undefined = ILiquidityProviderRegistryContract.deployedBytecode, - ) { - super( - 'ILiquidityProviderRegistry', - ILiquidityProviderRegistryContract.ABI(), - address, - supportedProvider, - txDefaults, - logDecodeDependencies, - deployedBytecode, - ); - classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); - ILiquidityProviderRegistryContract.ABI().forEach((item, index) => { - if (item.type === 'function') { - const methodAbi = item as MethodAbi; - this._methodABIIndex[methodAbi.name] = index; - } - }); - } -} - -// tslint:disable:max-file-line-count -// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align -// tslint:enable:trailing-comma whitespace no-trailing-whitespace diff --git a/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts b/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts index e0da11d70b..caf08d2335 100644 --- a/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts +++ b/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts @@ -36,7 +36,6 @@ import * as ethers from 'ethers'; // tslint:enable:no-unused-variable export type IZeroExEventArgs = - | IZeroExLiquidityProviderForMarketUpdatedEventArgs | IZeroExMetaTransactionExecutedEventArgs | IZeroExMigratedEventArgs | IZeroExOwnershipTransferredEventArgs @@ -46,7 +45,6 @@ export type IZeroExEventArgs = | IZeroExTransformerDeployerUpdatedEventArgs; export enum IZeroExEvents { - LiquidityProviderForMarketUpdated = 'LiquidityProviderForMarketUpdated', MetaTransactionExecuted = 'MetaTransactionExecuted', Migrated = 'Migrated', OwnershipTransferred = 'OwnershipTransferred', @@ -56,12 +54,6 @@ export enum IZeroExEvents { TransformerDeployerUpdated = 'TransformerDeployerUpdated', } -export interface IZeroExLiquidityProviderForMarketUpdatedEventArgs extends DecodedLogArgs { - xAsset: string; - yAsset: string; - providerAddress: string; -} - export interface IZeroExMetaTransactionExecutedEventArgs extends DecodedLogArgs { hash: string; selector: string; @@ -219,29 +211,6 @@ export class IZeroExContract extends BaseContract { */ public static ABI(): ContractAbi { const abi = [ - { - anonymous: false, - inputs: [ - { - name: 'xAsset', - type: 'address', - indexed: true, - }, - { - name: 'yAsset', - type: 'address', - indexed: true, - }, - { - name: 'providerAddress', - type: 'address', - indexed: false, - }, - ], - name: 'LiquidityProviderForMarketUpdated', - outputs: [], - type: 'event', - }, { anonymous: false, inputs: [ @@ -728,27 +697,6 @@ export class IZeroExContract extends BaseContract { stateMutability: 'view', type: 'function', }, - { - inputs: [ - { - name: 'xAsset', - type: 'address', - }, - { - name: 'yAsset', - type: 'address', - }, - ], - name: 'getLiquidityProviderForMarket', - outputs: [ - { - name: 'providerAddress', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, { inputs: [ { @@ -1062,6 +1010,10 @@ export class IZeroExContract extends BaseContract { name: 'takerToken', type: 'address', }, + { + name: 'target', + type: 'address', + }, { name: 'recipient', type: 'address', @@ -1074,6 +1026,10 @@ export class IZeroExContract extends BaseContract { name: 'minBuyAmount', type: 'uint256', }, + { + name: 'auxiliaryData', + type: 'bytes', + }, ], name: 'sellToLiquidityProvider', outputs: [ @@ -1114,26 +1070,6 @@ export class IZeroExContract extends BaseContract { stateMutability: 'payable', type: 'function', }, - { - inputs: [ - { - name: 'xAsset', - type: 'address', - }, - { - name: 'yAsset', - type: 'address', - }, - { - name: 'providerAddress', - type: 'address', - }, - ], - name: 'setLiquidityProviderForMarket', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, { inputs: [ { @@ -1848,60 +1784,6 @@ export class IZeroExContract extends BaseContract { }, }; } - /** - * Returns the address of the liquidity provider for a market given - * (xAsset, yAsset), or reverts if pool does not exist. - * @param xAsset First asset managed by the liquidity provider. - * @param yAsset Second asset managed by the liquidity provider. - */ - public getLiquidityProviderForMarket(xAsset: string, yAsset: string): ContractTxFunctionObj { - const self = (this as any) as IZeroExContract; - assert.isString('xAsset', xAsset); - assert.isString('yAsset', yAsset); - const functionSignature = 'getLiquidityProviderForMarket(address,address)'; - - return { - async sendTransactionAsync( - txData?: Partial | undefined, - opts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( - { data: this.getABIEncodedTransactionData(), ...txData }, - this.estimateGasAsync.bind(this), - ); - if (opts.shouldValidate !== false) { - await this.callAsync(txDataWithDefaults); - } - return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); - }, - awaitTransactionSuccessAsync( - txData?: Partial, - opts: AwaitTransactionSuccessOpts = { shouldValidate: true }, - ): PromiseWithTransactionHash { - return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts); - }, - async estimateGasAsync(txData?: Partial | undefined): Promise { - const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ - data: this.getABIEncodedTransactionData(), - ...txData, - }); - return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); - }, - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { data: this.getABIEncodedTransactionData(), ...callData }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [xAsset.toLowerCase(), yAsset.toLowerCase()]); - }, - }; - } /** * Get the block at which a meta-transaction has been executed. * @param mtx The meta-transaction. @@ -2606,20 +2488,38 @@ export class IZeroExContract extends BaseContract { }, }; } + /** + * Sells `sellAmount` of `takerToken` to the liquidity provider + * at the given `target`. + * @param makerToken The token being bought. + * @param takerToken The token being sold. + * @param target The address of the on-chain liquidity provider to trade + * with. + * @param recipient The recipient of the bought tokens. If equal to + * address(0), `msg.sender` is assumed to be the recipient. + * @param sellAmount The amount of `takerToken` to sell. + * @param minBuyAmount The minimum acceptable amount of `makerToken` to + * buy. Reverts if this amount is not satisfied. + * @param auxiliaryData Auxiliary data supplied to the `target` contract. + */ public sellToLiquidityProvider( makerToken: string, takerToken: string, + target: string, recipient: string, sellAmount: BigNumber, minBuyAmount: BigNumber, + auxiliaryData: string, ): ContractTxFunctionObj { const self = (this as any) as IZeroExContract; assert.isString('makerToken', makerToken); assert.isString('takerToken', takerToken); + assert.isString('target', target); assert.isString('recipient', recipient); assert.isBigNumber('sellAmount', sellAmount); assert.isBigNumber('minBuyAmount', minBuyAmount); - const functionSignature = 'sellToLiquidityProvider(address,address,address,uint256,uint256)'; + assert.isString('auxiliaryData', auxiliaryData); + const functionSignature = 'sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)'; return { async sendTransactionAsync( @@ -2662,9 +2562,11 @@ export class IZeroExContract extends BaseContract { return self._strictEncodeArguments(functionSignature, [ makerToken.toLowerCase(), takerToken.toLowerCase(), + target.toLowerCase(), recipient.toLowerCase(), sellAmount, minBuyAmount, + auxiliaryData, ]); }, }; @@ -2731,70 +2633,6 @@ export class IZeroExContract extends BaseContract { }, }; } - /** - * Sets address of the liquidity provider for a market given - * (xAsset, yAsset). - * @param xAsset First asset managed by the liquidity provider. - * @param yAsset Second asset managed by the liquidity provider. - * @param providerAddress Address of the liquidity provider. - */ - public setLiquidityProviderForMarket( - xAsset: string, - yAsset: string, - providerAddress: string, - ): ContractTxFunctionObj { - const self = (this as any) as IZeroExContract; - assert.isString('xAsset', xAsset); - assert.isString('yAsset', yAsset); - assert.isString('providerAddress', providerAddress); - const functionSignature = 'setLiquidityProviderForMarket(address,address,address)'; - - return { - async sendTransactionAsync( - txData?: Partial | undefined, - opts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( - { data: this.getABIEncodedTransactionData(), ...txData }, - this.estimateGasAsync.bind(this), - ); - if (opts.shouldValidate !== false) { - await this.callAsync(txDataWithDefaults); - } - return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); - }, - awaitTransactionSuccessAsync( - txData?: Partial, - opts: AwaitTransactionSuccessOpts = { shouldValidate: true }, - ): PromiseWithTransactionHash { - return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts); - }, - async estimateGasAsync(txData?: Partial | undefined): Promise { - const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ - data: this.getABIEncodedTransactionData(), - ...txData, - }); - return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); - }, - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { data: this.getABIEncodedTransactionData(), ...callData }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - xAsset.toLowerCase(), - yAsset.toLowerCase(), - providerAddress.toLowerCase(), - ]); - }, - }; - } /** * Replace the optional signer for `transformERC20()` calldata. * Only callable by the owner. diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 1f19988892..f4025e4d01 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -125,7 +125,6 @@ export { IZeroExContract, IZeroExEventArgs, IZeroExEvents, - IZeroExLiquidityProviderForMarketUpdatedEventArgs, IZeroExMetaTransactionExecutedEventArgs, IZeroExMigratedEventArgs, IZeroExOwnershipTransferredEventArgs, diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json index c1489f4f49..cdda491061 100644 --- a/packages/migrations/CHANGELOG.json +++ b/packages/migrations/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "6.5.0", + "changes": [ + { + "note": "Add `exchangeProxyLiquidityProviderSandbox` address", + "pr": 16 + } + ] + }, { "timestamp": 1604385937, "version": "6.4.7", diff --git a/packages/migrations/src/migration.ts b/packages/migrations/src/migration.ts index 066e0499bb..58d568614d 100644 --- a/packages/migrations/src/migration.ts +++ b/packages/migrations/src/migration.ts @@ -402,6 +402,7 @@ export async function runMigrationsAsync( exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress, exchangeProxyTransformerDeployer: txDefaults.from, exchangeProxyFlashWallet: exchangeProxyFlashWalletAddress, + exchangeProxyLiquidityProviderSandbox: NULL_ADDRESS, transformers: { wethTransformer: wethTransformer.address, payTakerTransformer: payTakerTransformer.address,