From 817049456ccda54b04a062737ce56700008984a8 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Wed, 26 Feb 2020 16:55:19 -0800 Subject: [PATCH 1/2] Get liquidity provider from registry in the sampler --- contracts/erc20-bridge-sampler/CHANGELOG.json | 4 ++ .../contracts/src/ERC20BridgeSampler.sol | 41 +++++++++++++++++-- .../src/ILiquidityProviderRegistry.sol | 36 ++++++++++++++++ contracts/erc20-bridge-sampler/package.json | 4 +- .../erc20-bridge-sampler/test/artifacts.ts | 2 + .../erc20-bridge-sampler/test/wrappers.ts | 1 + contracts/erc20-bridge-sampler/tsconfig.json | 1 + 7 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 contracts/erc20-bridge-sampler/contracts/src/ILiquidityProviderRegistry.sol diff --git a/contracts/erc20-bridge-sampler/CHANGELOG.json b/contracts/erc20-bridge-sampler/CHANGELOG.json index dd976b0b37..cb716c3d75 100644 --- a/contracts/erc20-bridge-sampler/CHANGELOG.json +++ b/contracts/erc20-bridge-sampler/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "Add generic liquidity provider sampling", "pr": 2487 + }, + { + "note": "Use liquidity provider registry in sampler", + "pr": 2499 } ] }, diff --git a/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol b/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol index 559d3f3c63..fd3b23d781 100644 --- a/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol +++ b/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol @@ -31,6 +31,7 @@ import "./IKyberNetwork.sol"; import "./IUniswapExchangeQuotes.sol"; import "./ICurve.sol"; import "./ILiquidityProvider.sol"; +import "./ILiquidityProviderRegistry.sol"; contract ERC20BridgeSampler is @@ -435,14 +436,14 @@ contract ERC20BridgeSampler is } /// @dev Sample sell quotes from an arbitrary on-chain liquidity provider. - /// @param providerAddress Address of the liquidity provider contract. + /// @param registryAddress Address of the liquidity provider registry contract. /// @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 sampleSellsFromLiquidityProvider( - address providerAddress, + address registryAddress, address takerToken, address makerToken, uint256[] memory takerTokenAmounts @@ -451,6 +452,12 @@ contract ERC20BridgeSampler is view returns (uint256[] memory makerTokenAmounts) { + address providerAddress = getLiquidityProviderFromRegistry( + registryAddress, + takerToken, + makerToken + ); + uint256 numSamples = takerTokenAmounts.length; makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { @@ -474,14 +481,14 @@ contract ERC20BridgeSampler is } /// @dev Sample buy quotes from an arbitrary on-chain liquidity provider. - /// @param providerAddress Address of the liquidity provider contract. + /// @param registryAddress Address of the liquidity provider registry contract. /// @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 sampleBuysFromLiquidityProvider( - address providerAddress, + address registryAddress, address takerToken, address makerToken, uint256[] memory makerTokenAmounts @@ -490,6 +497,12 @@ contract ERC20BridgeSampler is view returns (uint256[] memory takerTokenAmounts) { + address providerAddress = getLiquidityProviderFromRegistry( + registryAddress, + takerToken, + makerToken + ); + uint256 numSamples = makerTokenAmounts.length; takerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { @@ -512,6 +525,26 @@ contract ERC20BridgeSampler is } } + /// @dev Returns the address of a liquidity provider for the given market + /// (takerToken, makerToken), from a registry of liquidity providers. + /// @param takerToken Taker asset managed by liquidity provider. + /// @param makerToken Maker asset managed by liquidity provider. + /// @return Address of the liquidity provider. + function getLiquidityProviderFromRegistry( + address registryAddress, + address takerToken, + address makerToken + ) + public + view + returns (address) + { + return ILiquidityProviderRegistry(registryAddress).getLiquidityProviderForMarket( + takerToken, + makerToken + ); + } + /// @dev Overridable way to get token decimals. /// @param tokenAddress Address of the token. /// @return decimals The decimal places for the token. diff --git a/contracts/erc20-bridge-sampler/contracts/src/ILiquidityProviderRegistry.sol b/contracts/erc20-bridge-sampler/contracts/src/ILiquidityProviderRegistry.sol new file mode 100644 index 0000000000..22a39299b1 --- /dev/null +++ b/contracts/erc20-bridge-sampler/contracts/src/ILiquidityProviderRegistry.sol @@ -0,0 +1,36 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.9; + + +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 Address of the liquidity provider. + function getLiquidityProviderForMarket( + address takerToken, + address makerToken + ) + external + view + returns (address providerAddress); +} diff --git a/contracts/erc20-bridge-sampler/package.json b/contracts/erc20-bridge-sampler/package.json index 46906d6519..1a348974ae 100644 --- a/contracts/erc20-bridge-sampler/package.json +++ b/contracts/erc20-bridge-sampler/package.json @@ -36,9 +36,9 @@ "compile:truffle": "truffle compile" }, "config": { - "publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler", + "publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|ILiquidityProvider|IUniswapExchangeQuotes|TestERC20BridgeSampler).json" + "abis": "./test/generated-artifacts/@(ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json" }, "repository": { "type": "git", diff --git a/contracts/erc20-bridge-sampler/test/artifacts.ts b/contracts/erc20-bridge-sampler/test/artifacts.ts index 6e9a15445c..2ed14d12a6 100644 --- a/contracts/erc20-bridge-sampler/test/artifacts.ts +++ b/contracts/erc20-bridge-sampler/test/artifacts.ts @@ -12,6 +12,7 @@ import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSa 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 IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json'; import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json'; export const artifacts = { @@ -22,6 +23,7 @@ export const artifacts = { IEth2Dai: IEth2Dai as ContractArtifact, IKyberNetwork: IKyberNetwork as ContractArtifact, ILiquidityProvider: ILiquidityProvider as ContractArtifact, + ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact, IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact, TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact, }; diff --git a/contracts/erc20-bridge-sampler/test/wrappers.ts b/contracts/erc20-bridge-sampler/test/wrappers.ts index 55db751e47..4465c09dfd 100644 --- a/contracts/erc20-bridge-sampler/test/wrappers.ts +++ b/contracts/erc20-bridge-sampler/test/wrappers.ts @@ -10,5 +10,6 @@ export * from '../test/generated-wrappers/i_erc20_bridge_sampler'; 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_uniswap_exchange_quotes'; export * from '../test/generated-wrappers/test_erc20_bridge_sampler'; diff --git a/contracts/erc20-bridge-sampler/tsconfig.json b/contracts/erc20-bridge-sampler/tsconfig.json index a8cc5145ea..949000bd81 100644 --- a/contracts/erc20-bridge-sampler/tsconfig.json +++ b/contracts/erc20-bridge-sampler/tsconfig.json @@ -12,6 +12,7 @@ "test/generated-artifacts/IEth2Dai.json", "test/generated-artifacts/IKyberNetwork.json", "test/generated-artifacts/ILiquidityProvider.json", + "test/generated-artifacts/ILiquidityProviderRegistry.json", "test/generated-artifacts/IUniswapExchangeQuotes.json", "test/generated-artifacts/TestERC20BridgeSampler.json" ], From a47c031ad10fb4937c8c00ae43317a2215618f6b Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Thu, 27 Feb 2020 10:33:13 -0800 Subject: [PATCH 2/2] Catch reverts when calling registry --- .../contracts/src/ERC20BridgeSampler.sol | 40 ++++++++++++++----- .../contracts/src/IERC20BridgeSampler.sol | 27 ++++++++++--- .../erc20-bridge-sampler/src/artifacts.ts | 4 ++ .../erc20-bridge-sampler/src/wrappers.ts | 2 + contracts/erc20-bridge-sampler/tsconfig.json | 2 + 5 files changed, 60 insertions(+), 15 deletions(-) diff --git a/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol b/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol index fd3b23d781..6eb1d318d5 100644 --- a/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol +++ b/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol @@ -24,6 +24,7 @@ import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "./IDevUtils.sol"; import "./IERC20BridgeSampler.sol"; import "./IEth2Dai.sol"; @@ -442,7 +443,7 @@ contract ERC20BridgeSampler is /// @param takerTokenAmounts Taker token sell amount for each sample. /// @return makerTokenAmounts Maker amounts bought at each taker token /// amount. - function sampleSellsFromLiquidityProvider( + function sampleSellsFromLiquidityProviderRegistry( address registryAddress, address takerToken, address makerToken, @@ -452,14 +453,21 @@ contract ERC20BridgeSampler is view returns (uint256[] memory makerTokenAmounts) { + // Initialize array of maker token amounts. + uint256 numSamples = takerTokenAmounts.length; + makerTokenAmounts = new uint256[](numSamples); + + // Query registry for provider address. address providerAddress = getLiquidityProviderFromRegistry( registryAddress, takerToken, makerToken ); + // If provider doesn't exist, return all zeros. + if (providerAddress == address(0)) { + return makerTokenAmounts; + } - uint256 numSamples = takerTokenAmounts.length; - makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { (bool didSucceed, bytes memory resultData) = providerAddress.staticcall.gas(DEFAULT_CALL_GAS)( @@ -487,7 +495,7 @@ contract ERC20BridgeSampler is /// @param makerTokenAmounts Maker token buy amount for each sample. /// @return takerTokenAmounts Taker amounts sold at each maker token /// amount. - function sampleBuysFromLiquidityProvider( + function sampleBuysFromLiquidityProviderRegistry( address registryAddress, address takerToken, address makerToken, @@ -497,14 +505,22 @@ contract ERC20BridgeSampler is view returns (uint256[] memory takerTokenAmounts) { + // Initialize array of taker token amounts. + uint256 numSamples = makerTokenAmounts.length; + takerTokenAmounts = new uint256[](numSamples); + + // Query registry for provider address. address providerAddress = getLiquidityProviderFromRegistry( registryAddress, takerToken, makerToken ); + // If provider doesn't exist, return all zeros. + if (providerAddress == address(0)) { + return takerTokenAmounts; + } - uint256 numSamples = makerTokenAmounts.length; - takerTokenAmounts = new uint256[](numSamples); + // Otherwise, query liquidity provider for quotes. for (uint256 i = 0; i < numSamples; i++) { (bool didSucceed, bytes memory resultData) = providerAddress.staticcall.gas(DEFAULT_CALL_GAS)( @@ -527,9 +543,10 @@ contract ERC20BridgeSampler is /// @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 Address of the liquidity provider. + /// @return providerAddress Address of the liquidity provider. function getLiquidityProviderFromRegistry( address registryAddress, address takerToken, @@ -537,12 +554,17 @@ contract ERC20BridgeSampler is ) public view - returns (address) + returns (address providerAddress) { - return ILiquidityProviderRegistry(registryAddress).getLiquidityProviderForMarket( + bytes memory callData = abi.encodeWithSelector( + ILiquidityProviderRegistry(0).getLiquidityProviderForMarket.selector, takerToken, makerToken ); + (bool didSucceed, bytes memory returnData) = registryAddress.staticcall(callData); + if (didSucceed) { + return LibBytes.readAddress(returnData, 0); + } } /// @dev Overridable way to get token decimals. diff --git a/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol b/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol index 7c12da6260..bdc0cb78a9 100644 --- a/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol +++ b/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol @@ -151,14 +151,14 @@ interface IERC20BridgeSampler { returns (uint256[] memory makerTokenAmounts); /// @dev Sample sell quotes from an arbitrary on-chain liquidity provider. - /// @param providerAddress Address of the liquidity provider contract. + /// @param registryAddress Address of the liquidity provider registry contract. /// @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 sampleSellsFromLiquidityProvider( - address providerAddress, + function sampleSellsFromLiquidityProviderRegistry( + address registryAddress, address takerToken, address makerToken, uint256[] calldata takerTokenAmounts @@ -168,14 +168,14 @@ interface IERC20BridgeSampler { returns (uint256[] memory makerTokenAmounts); /// @dev Sample buy quotes from an arbitrary on-chain liquidity provider. - /// @param providerAddress Address of the liquidity provider contract. + /// @param registryAddress Address of the liquidity provider registry contract. /// @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 sampleBuysFromLiquidityProvider( - address providerAddress, + function sampleBuysFromLiquidityProviderRegistry( + address registryAddress, address takerToken, address makerToken, uint256[] calldata makerTokenAmounts @@ -183,4 +183,19 @@ interface IERC20BridgeSampler { external view returns (uint256[] memory takerTokenAmounts); + + /// @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 + ) + external + view + returns (address providerAddress); } diff --git a/contracts/erc20-bridge-sampler/src/artifacts.ts b/contracts/erc20-bridge-sampler/src/artifacts.ts index 41366d2e0e..1f15319fd0 100644 --- a/contracts/erc20-bridge-sampler/src/artifacts.ts +++ b/contracts/erc20-bridge-sampler/src/artifacts.ts @@ -7,7 +7,11 @@ import { ContractArtifact } from 'ethereum-types'; import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json'; import * as IERC20BridgeSampler from '../generated-artifacts/IERC20BridgeSampler.json'; +import * as ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json'; +import * as ILiquidityProviderRegistry from '../generated-artifacts/ILiquidityProviderRegistry.json'; export const artifacts = { ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact, IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact, + ILiquidityProvider: ILiquidityProvider as ContractArtifact, + ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact, }; diff --git a/contracts/erc20-bridge-sampler/src/wrappers.ts b/contracts/erc20-bridge-sampler/src/wrappers.ts index d1921d6176..968f08623c 100644 --- a/contracts/erc20-bridge-sampler/src/wrappers.ts +++ b/contracts/erc20-bridge-sampler/src/wrappers.ts @@ -5,3 +5,5 @@ */ export * from '../generated-wrappers/erc20_bridge_sampler'; export * from '../generated-wrappers/i_erc20_bridge_sampler'; +export * from '../generated-wrappers/i_liquidity_provider'; +export * from '../generated-wrappers/i_liquidity_provider_registry'; diff --git a/contracts/erc20-bridge-sampler/tsconfig.json b/contracts/erc20-bridge-sampler/tsconfig.json index 949000bd81..c8e6f55115 100644 --- a/contracts/erc20-bridge-sampler/tsconfig.json +++ b/contracts/erc20-bridge-sampler/tsconfig.json @@ -5,6 +5,8 @@ "files": [ "generated-artifacts/ERC20BridgeSampler.json", "generated-artifacts/IERC20BridgeSampler.json", + "generated-artifacts/ILiquidityProvider.json", + "generated-artifacts/ILiquidityProviderRegistry.json", "test/generated-artifacts/ERC20BridgeSampler.json", "test/generated-artifacts/ICurve.json", "test/generated-artifacts/IDevUtils.json",