@0x/contracts-erc20-bridge-sampler
: Generic liquidity provider sampling (#2487)
* Add methods to Sampler contract to plug into generic on-chain liquidity provider
This commit is contained in:
parent
ac56038eca
commit
9a7c4b21a9
@ -35,7 +35,7 @@ contract ChaiBridge is
|
|||||||
/// @param from Address to transfer asset from.
|
/// @param from Address to transfer asset from.
|
||||||
/// @param to Address to transfer asset to.
|
/// @param to Address to transfer asset to.
|
||||||
/// @param amount Amount of asset to transfer.
|
/// @param amount Amount of asset to transfer.
|
||||||
/// @return success The magic bytes `0x37708e9b` if successful.
|
/// @return success The magic bytes `0xdc1600f3` if successful.
|
||||||
function bridgeTransferFrom(
|
function bridgeTransferFrom(
|
||||||
address /* tokenAddress */,
|
address /* tokenAddress */,
|
||||||
address from,
|
address from,
|
||||||
|
@ -30,7 +30,7 @@ contract IERC20Bridge {
|
|||||||
/// @param to Address to transfer asset to.
|
/// @param to Address to transfer asset to.
|
||||||
/// @param amount Amount of asset to transfer.
|
/// @param amount Amount of asset to transfer.
|
||||||
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
||||||
/// @return success The magic bytes `0x37708e9b` if successful.
|
/// @return success The magic bytes `0xdc1600f3` if successful.
|
||||||
function bridgeTransferFrom(
|
function bridgeTransferFrom(
|
||||||
address tokenAddress,
|
address tokenAddress,
|
||||||
address from,
|
address from,
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.5.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add generic liquidity provider sampling",
|
||||||
|
"pr": 2487
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1582677073,
|
"timestamp": 1582677073,
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
|
@ -30,6 +30,7 @@ import "./IEth2Dai.sol";
|
|||||||
import "./IKyberNetwork.sol";
|
import "./IKyberNetwork.sol";
|
||||||
import "./IUniswapExchangeQuotes.sol";
|
import "./IUniswapExchangeQuotes.sol";
|
||||||
import "./ICurve.sol";
|
import "./ICurve.sol";
|
||||||
|
import "./ILiquidityProvider.sol";
|
||||||
|
|
||||||
|
|
||||||
contract ERC20BridgeSampler is
|
contract ERC20BridgeSampler is
|
||||||
@ -47,6 +48,8 @@ contract ERC20BridgeSampler is
|
|||||||
/// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
|
/// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
|
||||||
/// So a reasonable ceil is 150k per token. Biggest Curve has 4 tokens.
|
/// So a reasonable ceil is 150k per token. Biggest Curve has 4 tokens.
|
||||||
uint256 constant internal CURVE_CALL_GAS = 600e3; // 600k
|
uint256 constant internal CURVE_CALL_GAS = 600e3; // 600k
|
||||||
|
/// @dev Default gas limit for liquidity provider calls.
|
||||||
|
uint256 constant internal DEFAULT_CALL_GAS = 200e3; // 200k
|
||||||
|
|
||||||
/// @dev Call multiple public functions on this contract in a single transaction.
|
/// @dev Call multiple public functions on this contract in a single transaction.
|
||||||
/// @param callDatas ABI-encoded call data for each function call.
|
/// @param callDatas ABI-encoded call data for each function call.
|
||||||
@ -431,6 +434,84 @@ contract ERC20BridgeSampler is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
|
||||||
|
/// @param providerAddress Address of the liquidity provider 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 takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory 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)(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
ILiquidityProvider(0).getSellQuote.selector,
|
||||||
|
takerToken,
|
||||||
|
makerToken,
|
||||||
|
takerTokenAmounts[i]
|
||||||
|
));
|
||||||
|
uint256 buyAmount = 0;
|
||||||
|
if (didSucceed) {
|
||||||
|
buyAmount = abi.decode(resultData, (uint256));
|
||||||
|
} else {
|
||||||
|
// Exit early if the amount is too high for the liquidity provider to serve
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
makerTokenAmounts[i] = buyAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
||||||
|
/// @param providerAddress Address of the liquidity provider 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 takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = makerTokenAmounts.length;
|
||||||
|
takerTokenAmounts = new uint256[](numSamples);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
(bool didSucceed, bytes memory resultData) =
|
||||||
|
providerAddress.staticcall.gas(DEFAULT_CALL_GAS)(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
ILiquidityProvider(0).getBuyQuote.selector,
|
||||||
|
takerToken,
|
||||||
|
makerToken,
|
||||||
|
makerTokenAmounts[i]
|
||||||
|
));
|
||||||
|
uint256 sellAmount = 0;
|
||||||
|
if (didSucceed) {
|
||||||
|
sellAmount = abi.decode(resultData, (uint256));
|
||||||
|
} else {
|
||||||
|
// Exit early if the amount is too high for the liquidity provider to serve
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
takerTokenAmounts[i] = sellAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Overridable way to get token decimals.
|
/// @dev Overridable way to get token decimals.
|
||||||
/// @param tokenAddress Address of the token.
|
/// @param tokenAddress Address of the token.
|
||||||
/// @return decimals The decimal places for the token.
|
/// @return decimals The decimal places for the token.
|
||||||
|
@ -149,4 +149,38 @@ interface IERC20BridgeSampler {
|
|||||||
external
|
external
|
||||||
view
|
view
|
||||||
returns (uint256[] memory makerTokenAmounts);
|
returns (uint256[] memory makerTokenAmounts);
|
||||||
|
|
||||||
|
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
|
||||||
|
/// @param providerAddress Address of the liquidity provider 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 takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] calldata takerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory makerTokenAmounts);
|
||||||
|
|
||||||
|
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
||||||
|
/// @param providerAddress Address of the liquidity provider 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 takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] calldata makerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory takerTokenAmounts);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
@ -38,7 +38,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler",
|
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
"abis": "./test/generated-artifacts/@(ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
"abis": "./test/generated-artifacts/@(ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|ILiquidityProvider|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -11,6 +11,7 @@ import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
|
|||||||
import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSampler.json';
|
import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSampler.json';
|
||||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||||
|
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
||||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
||||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
|
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
@ -20,6 +21,7 @@ export const artifacts = {
|
|||||||
IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact,
|
IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact,
|
||||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||||
|
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@ -9,5 +9,6 @@ export * from '../test/generated-wrappers/i_dev_utils';
|
|||||||
export * from '../test/generated-wrappers/i_erc20_bridge_sampler';
|
export * from '../test/generated-wrappers/i_erc20_bridge_sampler';
|
||||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||||
export * from '../test/generated-wrappers/i_kyber_network';
|
export * from '../test/generated-wrappers/i_kyber_network';
|
||||||
|
export * from '../test/generated-wrappers/i_liquidity_provider';
|
||||||
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
|
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
|
||||||
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
|
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"test/generated-artifacts/IERC20BridgeSampler.json",
|
"test/generated-artifacts/IERC20BridgeSampler.json",
|
||||||
"test/generated-artifacts/IEth2Dai.json",
|
"test/generated-artifacts/IEth2Dai.json",
|
||||||
"test/generated-artifacts/IKyberNetwork.json",
|
"test/generated-artifacts/IKyberNetwork.json",
|
||||||
|
"test/generated-artifacts/ILiquidityProvider.json",
|
||||||
"test/generated-artifacts/IUniswapExchangeQuotes.json",
|
"test/generated-artifacts/IUniswapExchangeQuotes.json",
|
||||||
"test/generated-artifacts/TestERC20BridgeSampler.json"
|
"test/generated-artifacts/TestERC20BridgeSampler.json"
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user