@0x/contracts-erc20-bridge-sampler
: Add UniswapV2.
This commit is contained in:
parent
429f2bb8dd
commit
4066c17a0f
@ -17,6 +17,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Use `searchBestRate` in Kyber samples. Return 0 when Uniswap/Eth2Dai reserve",
|
"note": "Use `searchBestRate` in Kyber samples. Return 0 when Uniswap/Eth2Dai reserve",
|
||||||
"pr": 2575
|
"pr": 2575
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add UniswapV2",
|
||||||
|
"pr": 2595
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -34,6 +34,7 @@ import "./IUniswapExchangeQuotes.sol";
|
|||||||
import "./ICurve.sol";
|
import "./ICurve.sol";
|
||||||
import "./ILiquidityProvider.sol";
|
import "./ILiquidityProvider.sol";
|
||||||
import "./ILiquidityProviderRegistry.sol";
|
import "./ILiquidityProviderRegistry.sol";
|
||||||
|
import "./IUniswapV2Router.sol";
|
||||||
|
|
||||||
|
|
||||||
contract ERC20BridgeSampler is
|
contract ERC20BridgeSampler is
|
||||||
@ -46,6 +47,8 @@ contract ERC20BridgeSampler is
|
|||||||
uint256 constant internal KYBER_CALL_GAS = 1500e3; // 1.5m
|
uint256 constant internal KYBER_CALL_GAS = 1500e3; // 1.5m
|
||||||
/// @dev Gas limit for Uniswap calls.
|
/// @dev Gas limit for Uniswap calls.
|
||||||
uint256 constant internal UNISWAP_CALL_GAS = 150e3; // 150k
|
uint256 constant internal UNISWAP_CALL_GAS = 150e3; // 150k
|
||||||
|
/// @dev Gas limit for UniswapV2 calls.
|
||||||
|
uint256 constant internal UNISWAPV2_CALL_GAS = 150e3; // 150k
|
||||||
/// @dev Base gas limit for Eth2Dai calls.
|
/// @dev Base gas limit for Eth2Dai calls.
|
||||||
uint256 constant internal ETH2DAI_CALL_GAS = 1000e3; // 1m
|
uint256 constant internal ETH2DAI_CALL_GAS = 1000e3; // 1m
|
||||||
/// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
|
/// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
|
||||||
@ -645,6 +648,74 @@ contract ERC20BridgeSampler is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Sample sell quotes from UniswapV2.
|
||||||
|
/// @param path Token route.
|
||||||
|
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||||
|
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||||
|
/// amount.
|
||||||
|
function sampleSellsFromUniswapV2(
|
||||||
|
address[] memory path,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
(bool didSucceed, bytes memory resultData) =
|
||||||
|
_getUniswapV2RouterAddress().staticcall.gas(UNISWAPV2_CALL_GAS)(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
IUniswapV2Router(0).getAmountsOut.selector,
|
||||||
|
takerTokenAmounts[i],
|
||||||
|
path
|
||||||
|
));
|
||||||
|
uint256 buyAmount = 0;
|
||||||
|
if (didSucceed) {
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
buyAmount = abi.decode(resultData, (uint256[]))[path.length - 1];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
makerTokenAmounts[i] = buyAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Sample buy quotes from UniswapV2.
|
||||||
|
/// @param path Token route.
|
||||||
|
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||||
|
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||||
|
/// amount.
|
||||||
|
function sampleBuysFromUniswapV2(
|
||||||
|
address[] memory path,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = makerTokenAmounts.length;
|
||||||
|
takerTokenAmounts = new uint256[](numSamples);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
(bool didSucceed, bytes memory resultData) =
|
||||||
|
_getUniswapV2RouterAddress().staticcall.gas(UNISWAPV2_CALL_GAS)(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
IUniswapV2Router(0).getAmountsIn.selector,
|
||||||
|
makerTokenAmounts[i],
|
||||||
|
path
|
||||||
|
));
|
||||||
|
uint256 sellAmount = 0;
|
||||||
|
if (didSucceed) {
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
sellAmount = abi.decode(resultData, (uint256[]))[path.length - 1];
|
||||||
|
} else {
|
||||||
|
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.
|
||||||
|
@ -240,4 +240,30 @@ interface IERC20BridgeSampler {
|
|||||||
external
|
external
|
||||||
view
|
view
|
||||||
returns (address providerAddress);
|
returns (address providerAddress);
|
||||||
|
|
||||||
|
/// @dev Sample sell quotes from UniswapV2.
|
||||||
|
/// @param path Token route.
|
||||||
|
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||||
|
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||||
|
/// amount.
|
||||||
|
function sampleSellsFromUniswapV2(
|
||||||
|
address[] calldata path,
|
||||||
|
uint256[] calldata takerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory makerTokenAmounts);
|
||||||
|
|
||||||
|
/// @dev Sample buy quotes from UniswapV2.
|
||||||
|
/// @param path Token route.
|
||||||
|
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||||
|
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||||
|
/// amount.
|
||||||
|
function sampleBuysFromUniswapV2(
|
||||||
|
address[] calldata path,
|
||||||
|
uint256[] calldata makerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory takerTokenAmounts);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 IUniswapV2Router {
|
||||||
|
|
||||||
|
function getAmountsOut(uint256 amountIn, address[] calldata path)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory amounts);
|
||||||
|
|
||||||
|
function getAmountsIn(uint256 amountOut, address[] calldata path)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory amounts);
|
||||||
|
}
|
@ -25,6 +25,7 @@ import "../src/ERC20BridgeSampler.sol";
|
|||||||
import "../src/IEth2Dai.sol";
|
import "../src/IEth2Dai.sol";
|
||||||
import "../src/IDevUtils.sol";
|
import "../src/IDevUtils.sol";
|
||||||
import "../src/IKyberNetworkProxy.sol";
|
import "../src/IKyberNetworkProxy.sol";
|
||||||
|
import "../src/IUniswapV2Router.sol";
|
||||||
|
|
||||||
|
|
||||||
library LibDeterministicQuotes {
|
library LibDeterministicQuotes {
|
||||||
@ -194,6 +195,55 @@ contract TestERC20BridgeSamplerUniswapExchange is
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
contract TestERC20BridgeSamplerUniswapV2Router is
|
||||||
|
IUniswapV2Router,
|
||||||
|
DeploymentConstants,
|
||||||
|
FailTrigger
|
||||||
|
{
|
||||||
|
bytes32 constant private SALT = 0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1;
|
||||||
|
|
||||||
|
// Deterministic `IUniswapV2Router.getAmountsOut()`.
|
||||||
|
function getAmountsOut(uint256 amountIn, address[] calldata path)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory amounts)
|
||||||
|
{
|
||||||
|
require(path.length >= 2, "PATH_TOO_SHORT");
|
||||||
|
_revertIfShouldFail();
|
||||||
|
amounts = new uint256[](path.length);
|
||||||
|
amounts[0] = amountIn;
|
||||||
|
for (uint256 i = 0; i < path.length - 1; ++i) {
|
||||||
|
amounts[i + 1] = LibDeterministicQuotes.getDeterministicSellQuote(
|
||||||
|
SALT,
|
||||||
|
path[i],
|
||||||
|
path[i + 1],
|
||||||
|
amounts[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic `IUniswapV2Router.getAmountsInt()`.
|
||||||
|
function getAmountsIn(uint256 amountOut, address[] calldata path)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256[] memory amounts)
|
||||||
|
{
|
||||||
|
require(path.length >= 2, "PATH_TOO_SHORT");
|
||||||
|
_revertIfShouldFail();
|
||||||
|
amounts = new uint256[](path.length);
|
||||||
|
amounts[0] = amountOut;
|
||||||
|
for (uint256 i = 0; i < path.length - 1; ++i) {
|
||||||
|
amounts[i + 1] = LibDeterministicQuotes.getDeterministicBuyQuote(
|
||||||
|
SALT,
|
||||||
|
path[i],
|
||||||
|
path[i + 1],
|
||||||
|
amounts[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
contract TestERC20BridgeSamplerKyberNetwork is
|
contract TestERC20BridgeSamplerKyberNetwork is
|
||||||
IKyberNetwork,
|
IKyberNetwork,
|
||||||
DeploymentConstants,
|
DeploymentConstants,
|
||||||
@ -325,6 +375,7 @@ contract TestERC20BridgeSampler is
|
|||||||
FailTrigger
|
FailTrigger
|
||||||
{
|
{
|
||||||
TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
|
TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
|
||||||
|
TestERC20BridgeSamplerUniswapV2Router public uniswapV2Router;
|
||||||
TestERC20BridgeSamplerEth2Dai public eth2Dai;
|
TestERC20BridgeSamplerEth2Dai public eth2Dai;
|
||||||
TestERC20BridgeSamplerKyberNetwork public kyber;
|
TestERC20BridgeSamplerKyberNetwork public kyber;
|
||||||
|
|
||||||
@ -332,6 +383,7 @@ contract TestERC20BridgeSampler is
|
|||||||
|
|
||||||
constructor() public ERC20BridgeSampler(address(this)) {
|
constructor() public ERC20BridgeSampler(address(this)) {
|
||||||
uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
|
uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
|
||||||
|
uniswapV2Router = new TestERC20BridgeSamplerUniswapV2Router();
|
||||||
eth2Dai = new TestERC20BridgeSamplerEth2Dai();
|
eth2Dai = new TestERC20BridgeSamplerEth2Dai();
|
||||||
kyber = new TestERC20BridgeSamplerKyberNetwork();
|
kyber = new TestERC20BridgeSamplerKyberNetwork();
|
||||||
}
|
}
|
||||||
@ -399,6 +451,15 @@ contract TestERC20BridgeSampler is
|
|||||||
return address(uniswap);
|
return address(uniswap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overriden to point to a custom contract.
|
||||||
|
function _getUniswapV2RouterAddress()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (address uniswapV2RouterAddress)
|
||||||
|
{
|
||||||
|
return address(uniswapV2Router);
|
||||||
|
}
|
||||||
|
|
||||||
// Overriden to point to a custom contract.
|
// Overriden to point to a custom contract.
|
||||||
function _getKyberNetworkProxyAddress()
|
function _getKyberNetworkProxyAddress()
|
||||||
internal
|
internal
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
||||||
"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/@(DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IKyberNetworkProxy|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
"abis": "./test/generated-artifacts/@(DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IKyberNetworkProxy|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|IUniswapV2Router|TestERC20BridgeSampler).json"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -17,6 +17,7 @@ import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkPr
|
|||||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
||||||
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
|
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
|
||||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
||||||
|
import * as IUniswapV2Router from '../test/generated-artifacts/IUniswapV2Router.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 = {
|
||||||
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
||||||
@ -31,5 +32,6 @@ export const artifacts = {
|
|||||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
||||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||||
|
IUniswapV2Router: IUniswapV2Router as ContractArtifact,
|
||||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@ -28,6 +28,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const KYBER_SALT = '0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7';
|
const KYBER_SALT = '0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7';
|
||||||
const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7';
|
const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7';
|
||||||
const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab';
|
const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab';
|
||||||
|
const UNISWAP_V2_SALT = '0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1';
|
||||||
const ERC20_PROXY_ID = '0xf47261b0';
|
const ERC20_PROXY_ID = '0xf47261b0';
|
||||||
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
|
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
|
||||||
const MAKER_TOKEN = randomAddress();
|
const MAKER_TOKEN = randomAddress();
|
||||||
@ -191,6 +192,22 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
return quotes;
|
return quotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDeterministicUniswapV2SellQuote(path: string[], sellAmount: BigNumber): BigNumber {
|
||||||
|
let bought = sellAmount;
|
||||||
|
for (let i = 0; i < path.length - 1; ++i) {
|
||||||
|
bought = getDeterministicSellQuote(UNISWAP_V2_SALT, path[i], path[i + 1], bought);
|
||||||
|
}
|
||||||
|
return bought;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDeterministicUniswapV2BuyQuote(path: string[], buyAmount: BigNumber): BigNumber {
|
||||||
|
let sold = buyAmount;
|
||||||
|
for (let i = 0; i < path.length - 1; ++i) {
|
||||||
|
sold = getDeterministicBuyQuote(UNISWAP_V2_SALT, path[i], path[i + 1], sold);
|
||||||
|
}
|
||||||
|
return sold;
|
||||||
|
}
|
||||||
|
|
||||||
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
||||||
const hash = getPackedHash(hexUtils.leftPad(order.salt));
|
const hash = getPackedHash(hexUtils.leftPad(order.salt));
|
||||||
const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
|
const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
|
||||||
@ -926,6 +943,86 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
blockchainTests.resets('sampleSellsFromUniswapV2()', () => {
|
||||||
|
function predictSellQuotes(path: string[], sellAmounts: BigNumber[]): BigNumber[] {
|
||||||
|
return sellAmounts.map(a => getDeterministicUniswapV2SellQuote(path, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
it('can return no quotes', async () => {
|
||||||
|
const quotes = await testContract.sampleSellsFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], []).callAsync();
|
||||||
|
expect(quotes).to.deep.eq([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can quote token -> token', async () => {
|
||||||
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
|
const expectedQuotes = predictSellQuotes([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts);
|
||||||
|
const quotes = await testContract
|
||||||
|
.sampleSellsFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts)
|
||||||
|
.callAsync();
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns zero if token -> token fails', async () => {
|
||||||
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
|
await enableFailTriggerAsync();
|
||||||
|
const quotes = await testContract
|
||||||
|
.sampleSellsFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts)
|
||||||
|
.callAsync();
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can quote token -> token -> token', async () => {
|
||||||
|
const intermediateToken = randomAddress();
|
||||||
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
|
const expectedQuotes = predictSellQuotes([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts);
|
||||||
|
const quotes = await testContract
|
||||||
|
.sampleSellsFromUniswapV2([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts)
|
||||||
|
.callAsync();
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
blockchainTests.resets('sampleBuysFromUniswapV2()', () => {
|
||||||
|
function predictBuyQuotes(path: string[], buyAmounts: BigNumber[]): BigNumber[] {
|
||||||
|
return buyAmounts.map(a => getDeterministicUniswapV2BuyQuote(path, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
it('can return no quotes', async () => {
|
||||||
|
const quotes = await testContract.sampleBuysFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], []).callAsync();
|
||||||
|
expect(quotes).to.deep.eq([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can quote token -> token', async () => {
|
||||||
|
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||||
|
const expectedQuotes = predictBuyQuotes([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts);
|
||||||
|
const quotes = await testContract
|
||||||
|
.sampleBuysFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts)
|
||||||
|
.callAsync();
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns zero if token -> token fails', async () => {
|
||||||
|
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||||
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
|
await enableFailTriggerAsync();
|
||||||
|
const quotes = await testContract
|
||||||
|
.sampleBuysFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts)
|
||||||
|
.callAsync();
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can quote token -> token -> token', async () => {
|
||||||
|
const intermediateToken = randomAddress();
|
||||||
|
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||||
|
const expectedQuotes = predictBuyQuotes([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts);
|
||||||
|
const quotes = await testContract
|
||||||
|
.sampleBuysFromUniswapV2([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts)
|
||||||
|
.callAsync();
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('batchCall()', () => {
|
describe('batchCall()', () => {
|
||||||
it('can call one function', async () => {
|
it('can call one function', async () => {
|
||||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||||
|
@ -15,4 +15,5 @@ export * from '../test/generated-wrappers/i_kyber_network_proxy';
|
|||||||
export * from '../test/generated-wrappers/i_liquidity_provider';
|
export * from '../test/generated-wrappers/i_liquidity_provider';
|
||||||
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
|
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
|
||||||
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
|
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
|
||||||
|
export * from '../test/generated-wrappers/i_uniswap_v2_router';
|
||||||
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
|
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"test/generated-artifacts/ILiquidityProvider.json",
|
"test/generated-artifacts/ILiquidityProvider.json",
|
||||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
||||||
"test/generated-artifacts/IUniswapExchangeQuotes.json",
|
"test/generated-artifacts/IUniswapExchangeQuotes.json",
|
||||||
|
"test/generated-artifacts/IUniswapV2Router.json",
|
||||||
"test/generated-artifacts/TestERC20BridgeSampler.json"
|
"test/generated-artifacts/TestERC20BridgeSampler.json"
|
||||||
],
|
],
|
||||||
"exclude": ["./deploy/solc/solc_bin"]
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"note": "Add UniswapV2 addresses to `DeploymentConstants`",
|
"note": "Add UniswapV2 addresses to `DeploymentConstants`",
|
||||||
"pr": "TODO"
|
"pr": 2595
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user