feat: better Kyber quotes (#2683)
* feat: Kyber rework * Get additional reserves per token
This commit is contained in:
parent
2f9b894d71
commit
a2f0d5eedf
@ -21,6 +21,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Added `MooniswapBridge`",
|
"note": "Added `MooniswapBridge`",
|
||||||
"pr": 2675
|
"pr": 2675
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Reworked `KyberBridge`",
|
||||||
|
"pr": 2683
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2020 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -45,6 +45,7 @@ contract KyberBridge is
|
|||||||
uint256 fromTokenBalance;
|
uint256 fromTokenBalance;
|
||||||
uint256 payableAmount;
|
uint256 payableAmount;
|
||||||
uint256 conversionRate;
|
uint256 conversionRate;
|
||||||
|
bytes hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Kyber ETH pseudo-address.
|
/// @dev Kyber ETH pseudo-address.
|
||||||
@ -85,47 +86,35 @@ contract KyberBridge is
|
|||||||
state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
|
state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
|
||||||
state.weth = IEtherToken(_getWethAddress());
|
state.weth = IEtherToken(_getWethAddress());
|
||||||
// Decode the bridge data to get the `fromTokenAddress`.
|
// Decode the bridge data to get the `fromTokenAddress`.
|
||||||
(state.fromTokenAddress) = abi.decode(bridgeData, (address));
|
(state.fromTokenAddress, state.hint) = abi.decode(bridgeData, (address, bytes));
|
||||||
// Query the balance of "from" tokens.
|
// Query the balance of "from" tokens.
|
||||||
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
||||||
if (state.fromTokenBalance == 0) {
|
if (state.fromTokenBalance == 0) {
|
||||||
// Return failure if no input tokens.
|
// Return failure if no input tokens.
|
||||||
return BRIDGE_FAILED;
|
return BRIDGE_FAILED;
|
||||||
}
|
}
|
||||||
// Compute the conversion rate, expressed in 18 decimals.
|
|
||||||
// The sequential notation is to get around stack limits.
|
|
||||||
state.conversionRate = KYBER_RATE_BASE;
|
|
||||||
state.conversionRate = state.conversionRate.safeMul(amount);
|
|
||||||
state.conversionRate = state.conversionRate.safeMul(
|
|
||||||
10 ** uint256(LibERC20Token.decimals(state.fromTokenAddress))
|
|
||||||
);
|
|
||||||
state.conversionRate = state.conversionRate.safeDiv(state.fromTokenBalance);
|
|
||||||
state.conversionRate = state.conversionRate.safeDiv(
|
|
||||||
10 ** uint256(LibERC20Token.decimals(toTokenAddress))
|
|
||||||
);
|
|
||||||
if (state.fromTokenAddress == toTokenAddress) {
|
if (state.fromTokenAddress == toTokenAddress) {
|
||||||
// Just transfer the tokens if they're the same.
|
// Just transfer the tokens if they're the same.
|
||||||
LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
|
LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
|
||||||
return BRIDGE_SUCCESS;
|
return BRIDGE_SUCCESS;
|
||||||
} else if (state.fromTokenAddress != address(state.weth)) {
|
}
|
||||||
// If the input token is not WETH, grant an allowance to the exchange
|
if (state.fromTokenAddress == address(state.weth)) {
|
||||||
// to spend them.
|
// From WETH
|
||||||
|
state.fromTokenAddress = KYBER_ETH_ADDRESS;
|
||||||
|
state.payableAmount = state.fromTokenBalance;
|
||||||
|
state.weth.withdraw(state.fromTokenBalance);
|
||||||
|
} else {
|
||||||
LibERC20Token.approveIfBelow(
|
LibERC20Token.approveIfBelow(
|
||||||
state.fromTokenAddress,
|
state.fromTokenAddress,
|
||||||
address(state.kyber),
|
address(state.kyber),
|
||||||
state.fromTokenBalance
|
state.fromTokenBalance
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
// If the input token is WETH, unwrap it and attach it to the call.
|
|
||||||
state.fromTokenAddress = KYBER_ETH_ADDRESS;
|
|
||||||
state.payableAmount = state.fromTokenBalance;
|
|
||||||
state.weth.withdraw(state.fromTokenBalance);
|
|
||||||
}
|
}
|
||||||
bool isToTokenWeth = toTokenAddress == address(state.weth);
|
bool isToTokenWeth = toTokenAddress == address(state.weth);
|
||||||
|
|
||||||
// Try to sell all of this contract's input token balance through
|
// Try to sell all of this contract's input token balance through
|
||||||
// `KyberNetworkProxy.trade()`.
|
// `KyberNetworkProxy.trade()`.
|
||||||
uint256 boughtAmount = state.kyber.trade.value(state.payableAmount)(
|
uint256 boughtAmount = state.kyber.tradeWithHint.value(state.payableAmount)(
|
||||||
// Input token.
|
// Input token.
|
||||||
state.fromTokenAddress,
|
state.fromTokenAddress,
|
||||||
// Sell amount.
|
// Sell amount.
|
||||||
@ -137,11 +126,11 @@ contract KyberBridge is
|
|||||||
isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
|
isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
|
||||||
// Buy as much as possible.
|
// Buy as much as possible.
|
||||||
uint256(-1),
|
uint256(-1),
|
||||||
// Compute the minimum conversion rate, which is expressed in units with
|
// The minimum conversion rate
|
||||||
// 18 decimal places.
|
1,
|
||||||
state.conversionRate,
|
|
||||||
// No affiliate address.
|
// No affiliate address.
|
||||||
address(0)
|
address(0),
|
||||||
|
state.hint
|
||||||
);
|
);
|
||||||
// Wrap ETH output and transfer to recipient.
|
// Wrap ETH output and transfer to recipient.
|
||||||
if (isToTokenWeth) {
|
if (isToTokenWeth) {
|
||||||
@ -173,4 +162,5 @@ contract KyberBridge is
|
|||||||
{
|
{
|
||||||
return LEGACY_WALLET_MAGIC_VALUE;
|
return LEGACY_WALLET_MAGIC_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,5 +42,31 @@ interface IKyberNetworkProxy {
|
|||||||
)
|
)
|
||||||
external
|
external
|
||||||
payable
|
payable
|
||||||
returns(uint256 boughtAmount);
|
returns (uint256 boughtAmount);
|
||||||
|
|
||||||
|
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens
|
||||||
|
/// using a hint for the reserve.
|
||||||
|
/// @param sellTokenAddress Token to sell.
|
||||||
|
/// @param sellAmount Amount of tokens to sell.
|
||||||
|
/// @param buyTokenAddress Token to buy.
|
||||||
|
/// @param recipientAddress Address to send bought tokens to.
|
||||||
|
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
|
||||||
|
/// @param minConversionRate The minimal conversion rate. If actual rate
|
||||||
|
/// is lower, trade is canceled.
|
||||||
|
/// @param walletId The wallet ID to send part of the fees
|
||||||
|
/// @param hint The hint for the selective inclusion (or exclusion) of reserves
|
||||||
|
/// @return boughtAmount Amount of tokens bought.
|
||||||
|
function tradeWithHint(
|
||||||
|
address sellTokenAddress,
|
||||||
|
uint256 sellAmount,
|
||||||
|
address buyTokenAddress,
|
||||||
|
address payable recipientAddress,
|
||||||
|
uint256 maxBuyTokenAmount,
|
||||||
|
uint256 minConversionRate,
|
||||||
|
address payable walletId,
|
||||||
|
bytes calldata hint
|
||||||
|
)
|
||||||
|
external
|
||||||
|
payable
|
||||||
|
returns (uint256 boughtAmount);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2020 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -28,6 +28,8 @@ contract DeploymentConstants {
|
|||||||
address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||||
/// @dev Mainnet address of the KyberNetworkProxy contract.
|
/// @dev Mainnet address of the KyberNetworkProxy contract.
|
||||||
address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x9AAb3f75489902f3a48495025729a0AF77d4b11e;
|
address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x9AAb3f75489902f3a48495025729a0AF77d4b11e;
|
||||||
|
/// @dev Mainnet address of the KyberHintHandler contract.
|
||||||
|
address constant private KYBER_HINT_HANDLER_ADDRESS = 0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C;
|
||||||
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
|
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
|
||||||
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||||
/// @dev Mainnet address of the `UniswapV2Router01` contract.
|
/// @dev Mainnet address of the `UniswapV2Router01` contract.
|
||||||
@ -155,6 +157,16 @@ contract DeploymentConstants {
|
|||||||
return KYBER_NETWORK_PROXY_ADDRESS;
|
return KYBER_NETWORK_PROXY_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Overridable way to get the `KyberHintHandler` address.
|
||||||
|
/// @return kyberAddress The `IKyberHintHandler` address.
|
||||||
|
function _getKyberHintHandlerAddress()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (address hintHandlerAddress)
|
||||||
|
{
|
||||||
|
return KYBER_HINT_HANDLER_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Overridable way to get the WETH address.
|
/// @dev Overridable way to get the WETH address.
|
||||||
/// @return wethAddress The WETH address.
|
/// @return wethAddress The WETH address.
|
||||||
function _getWethAddress()
|
function _getWethAddress()
|
||||||
|
@ -73,6 +73,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Use on-chain sampling (sometimes) for Balancer",
|
"note": "Use on-chain sampling (sometimes) for Balancer",
|
||||||
"pr": 2647
|
"pr": 2647
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Re-worked `Kyber` quotes supporting multiple reserves",
|
||||||
|
"pr": 2683
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2020 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -21,9 +21,6 @@ pragma experimental ABIEncoderV2;
|
|||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||||
import "./interfaces/IKyberNetwork.sol";
|
import "./interfaces/IKyberNetwork.sol";
|
||||||
import "./interfaces/IKyberNetworkProxy.sol";
|
|
||||||
import "./interfaces/IKyberStorage.sol";
|
|
||||||
import "./interfaces/IKyberHintHandler.sol";
|
|
||||||
import "./ApproximateBuys.sol";
|
import "./ApproximateBuys.sol";
|
||||||
import "./SamplerUtils.sol";
|
import "./SamplerUtils.sol";
|
||||||
|
|
||||||
@ -34,73 +31,130 @@ contract KyberSampler is
|
|||||||
ApproximateBuys
|
ApproximateBuys
|
||||||
{
|
{
|
||||||
/// @dev Gas limit for Kyber calls.
|
/// @dev Gas limit for Kyber calls.
|
||||||
uint256 constant private KYBER_CALL_GAS = 1500e3; // 1.5m
|
uint256 constant private KYBER_CALL_GAS = 500e3; // 500k
|
||||||
/// @dev The Kyber Uniswap Reserve address
|
|
||||||
address constant private KYBER_UNISWAP_RESERVE = 0x31E085Afd48a1d6e51Cc193153d625e8f0514C7F;
|
|
||||||
/// @dev The Kyber Uniswap V2 Reserve address
|
|
||||||
address constant private KYBER_UNISWAPV2_RESERVE = 0x10908C875D865C66f271F5d3949848971c9595C9;
|
|
||||||
/// @dev The Kyber Eth2Dai Reserve address
|
|
||||||
address constant private KYBER_ETH2DAI_RESERVE = 0x1E158c0e93c30d24e918Ef83d1e0bE23595C3c0f;
|
|
||||||
|
|
||||||
/// @dev Sample sell quotes from Kyber.
|
/// @dev Sample sell quotes from Kyber.
|
||||||
|
/// @param reserveId The selected kyber reserve
|
||||||
/// @param takerToken Address of the taker token (what to sell).
|
/// @param takerToken Address of the taker token (what to sell).
|
||||||
/// @param makerToken Address of the maker token (what to buy).
|
/// @param makerToken Address of the maker token (what to buy).
|
||||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
/// @return hint The hint for the selected reserve
|
||||||
/// amount.
|
/// @return makerTokenAmounts Maker amounts bought at each taker token amount.
|
||||||
function sampleSellsFromKyberNetwork(
|
function sampleSellsFromKyberNetwork(
|
||||||
|
bytes32 reserveId,
|
||||||
address takerToken,
|
address takerToken,
|
||||||
address makerToken,
|
address makerToken,
|
||||||
uint256[] memory takerTokenAmounts
|
uint256[] memory takerTokenAmounts
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
view
|
view
|
||||||
returns (uint256[] memory makerTokenAmounts)
|
returns (bytes memory hint, uint256[] memory makerTokenAmounts)
|
||||||
{
|
{
|
||||||
_assertValidPair(makerToken, takerToken);
|
_assertValidPair(makerToken, takerToken);
|
||||||
uint256 numSamples = takerTokenAmounts.length;
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
makerTokenAmounts = new uint256[](numSamples);
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
address wethAddress = _getWethAddress();
|
hint = this.encodeKyberHint(reserveId, takerToken, makerToken);
|
||||||
uint256 value;
|
|
||||||
for (uint256 i = 0; i < numSamples; i++) {
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
if (takerToken == wethAddress || makerToken == wethAddress) {
|
uint256 value = this.sampleSellFromKyberNetwork(hint, takerToken, makerToken, takerTokenAmounts[i]);
|
||||||
// Direct ETH based trade
|
// Return early if the source has no liquidity
|
||||||
value = _sampleSellFromKyberNetwork(takerToken, makerToken, takerTokenAmounts[i]);
|
if (value == 0) {
|
||||||
} else {
|
return (hint, makerTokenAmounts);
|
||||||
// Hop to ETH
|
|
||||||
value = _sampleSellFromKyberNetwork(takerToken, wethAddress, takerTokenAmounts[i]);
|
|
||||||
if (value != 0) {
|
|
||||||
value = _sampleSellFromKyberNetwork(wethAddress, makerToken, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
makerTokenAmounts[i] = value;
|
makerTokenAmounts[i] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Sample buy quotes from Kyber.
|
/// @dev Sample buy quotes from Kyber.
|
||||||
|
/// @param reserveId The selected kyber reserve
|
||||||
/// @param takerToken Address of the taker token (what to sell).
|
/// @param takerToken Address of the taker token (what to sell).
|
||||||
/// @param makerToken Address of the maker token (what to buy).
|
/// @param makerToken Address of the maker token (what to buy).
|
||||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
/// @return hint The hint for the selected reserve
|
||||||
/// amount.
|
/// @return takerTokenAmounts Taker amounts sold at each maker token amount.
|
||||||
function sampleBuysFromKyberNetwork(
|
function sampleBuysFromKyberNetwork(
|
||||||
|
bytes32 reserveId,
|
||||||
address takerToken,
|
address takerToken,
|
||||||
address makerToken,
|
address makerToken,
|
||||||
uint256[] memory makerTokenAmounts
|
uint256[] memory makerTokenAmounts
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
view
|
view
|
||||||
returns (uint256[] memory takerTokenAmounts)
|
returns (bytes memory hint, uint256[] memory takerTokenAmounts)
|
||||||
{
|
{
|
||||||
_assertValidPair(makerToken, takerToken);
|
_assertValidPair(makerToken, takerToken);
|
||||||
return _sampleApproximateBuys(
|
hint = this.encodeKyberHint(reserveId, takerToken, makerToken);
|
||||||
|
takerTokenAmounts = _sampleApproximateBuys(
|
||||||
ApproximateBuyQuoteOpts({
|
ApproximateBuyQuoteOpts({
|
||||||
makerTokenData: abi.encode(makerToken),
|
makerTokenData: abi.encode(makerToken, hint),
|
||||||
takerTokenData: abi.encode(takerToken),
|
takerTokenData: abi.encode(takerToken, hint),
|
||||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromKyber
|
getSellQuoteCallback: _sampleSellForApproximateBuyFromKyber
|
||||||
}),
|
}),
|
||||||
makerTokenAmounts
|
makerTokenAmounts
|
||||||
);
|
);
|
||||||
|
return (hint, takerTokenAmounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeKyberHint(
|
||||||
|
bytes32 reserveId,
|
||||||
|
address takerToken,
|
||||||
|
address makerToken
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (bytes memory hint)
|
||||||
|
{
|
||||||
|
// Build a hint selecting the single reserve
|
||||||
|
IKyberHintHandler kyberHint = IKyberHintHandler(_getKyberHintHandlerAddress());
|
||||||
|
|
||||||
|
// All other reserves should be ignored with this hint
|
||||||
|
bytes32[] memory selectedReserves = new bytes32[](1);
|
||||||
|
selectedReserves[0] = reserveId;
|
||||||
|
|
||||||
|
bool didSucceed;
|
||||||
|
bytes memory resultData;
|
||||||
|
if (takerToken == _getWethAddress()) {
|
||||||
|
// ETH to Token
|
||||||
|
(didSucceed, resultData) =
|
||||||
|
address(kyberHint).staticcall.gas(KYBER_CALL_GAS)(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
IKyberHintHandler(0).buildEthToTokenHint.selector,
|
||||||
|
makerToken,
|
||||||
|
IKyberHintHandler.TradeType.MaskIn,
|
||||||
|
selectedReserves,
|
||||||
|
new uint256[](0)));
|
||||||
|
} else if (makerToken == _getWethAddress()) {
|
||||||
|
// Token to ETH
|
||||||
|
(didSucceed, resultData) =
|
||||||
|
address(kyberHint).staticcall.gas(KYBER_CALL_GAS)(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
IKyberHintHandler(0).buildTokenToEthHint.selector,
|
||||||
|
takerToken,
|
||||||
|
IKyberHintHandler.TradeType.MaskIn,
|
||||||
|
selectedReserves,
|
||||||
|
new uint256[](0)));
|
||||||
|
} else {
|
||||||
|
// Token to Token
|
||||||
|
// We use the same reserve both ways
|
||||||
|
(didSucceed, resultData) =
|
||||||
|
address(kyberHint).staticcall.gas(KYBER_CALL_GAS)(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
IKyberHintHandler(0).buildTokenToTokenHint.selector,
|
||||||
|
takerToken,
|
||||||
|
IKyberHintHandler.TradeType.MaskIn,
|
||||||
|
selectedReserves,
|
||||||
|
new uint256[](0),
|
||||||
|
makerToken,
|
||||||
|
IKyberHintHandler.TradeType.MaskIn,
|
||||||
|
selectedReserves,
|
||||||
|
new uint256[](0)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// If successful decode the hint
|
||||||
|
if (didSucceed) {
|
||||||
|
hint = abi.decode(resultData, (bytes));
|
||||||
|
}
|
||||||
|
return hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _sampleSellForApproximateBuyFromKyber(
|
function _sampleSellForApproximateBuyFromKyber(
|
||||||
@ -112,82 +166,40 @@ contract KyberSampler is
|
|||||||
view
|
view
|
||||||
returns (uint256 buyAmount)
|
returns (uint256 buyAmount)
|
||||||
{
|
{
|
||||||
|
(address makerToken, bytes memory hint) =
|
||||||
|
abi.decode(makerTokenData, (address, bytes));
|
||||||
|
(address takerToken, ) =
|
||||||
|
abi.decode(takerTokenData, (address, bytes));
|
||||||
(bool success, bytes memory resultData) =
|
(bool success, bytes memory resultData) =
|
||||||
address(this).staticcall(abi.encodeWithSelector(
|
address(this).staticcall(abi.encodeWithSelector(
|
||||||
this.sampleSellsFromKyberNetwork.selector,
|
this.sampleSellFromKyberNetwork.selector,
|
||||||
abi.decode(takerTokenData, (address)),
|
hint,
|
||||||
abi.decode(makerTokenData, (address)),
|
takerToken,
|
||||||
_toSingleValueArray(sellAmount)
|
makerToken,
|
||||||
|
sellAmount
|
||||||
));
|
));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// solhint-disable-next-line indent
|
// solhint-disable-next-line indent
|
||||||
return abi.decode(resultData, (uint256[]))[0];
|
return abi.decode(resultData, (uint256));
|
||||||
}
|
}
|
||||||
|
|
||||||
function _appendToList(bytes32[] memory list, bytes32 item) private view returns (bytes32[] memory appendedList)
|
function sampleSellFromKyberNetwork(
|
||||||
{
|
bytes memory hint,
|
||||||
appendedList = new bytes32[](list.length + 1);
|
|
||||||
for (uint256 i = 0; i < list.length; i++) {
|
|
||||||
appendedList[i] = list[i];
|
|
||||||
}
|
|
||||||
appendedList[appendedList.length - 1] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _getKyberAddresses()
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (IKyberHintHandler kyberHint, IKyberStorage kyberStorage)
|
|
||||||
{
|
|
||||||
(, , kyberHint, kyberStorage, ,) = IKyberNetwork(
|
|
||||||
IKyberNetworkProxy(_getKyberNetworkProxyAddress()).kyberNetwork()).getContracts();
|
|
||||||
return (IKyberHintHandler(kyberHint), IKyberStorage(kyberStorage));
|
|
||||||
}
|
|
||||||
|
|
||||||
function _sampleSellFromKyberNetwork(
|
|
||||||
address takerToken,
|
address takerToken,
|
||||||
address makerToken,
|
address makerToken,
|
||||||
uint256 takerTokenAmount
|
uint256 takerTokenAmount
|
||||||
)
|
)
|
||||||
private
|
public
|
||||||
view
|
view
|
||||||
returns (uint256 makerTokenAmount)
|
returns (uint256 makerTokenAmount)
|
||||||
{
|
{
|
||||||
(IKyberHintHandler kyberHint, IKyberStorage kyberStorage) = _getKyberAddresses();
|
// If there is no hint do not continue
|
||||||
// Ban reserves which can clash with our internal aggregation
|
if (hint.length == 0) {
|
||||||
bytes32[] memory reserveIds = kyberStorage.getReserveIdsPerTokenSrc(
|
return 0;
|
||||||
takerToken == _getWethAddress() ? makerToken : takerToken
|
|
||||||
);
|
|
||||||
bytes32[] memory bannedReserveIds = new bytes32[](0);
|
|
||||||
// Poor mans resize and append
|
|
||||||
for (uint256 i = 0; i < reserveIds.length; i++) {
|
|
||||||
if (
|
|
||||||
reserveIds[i] == kyberStorage.getReserveId(KYBER_UNISWAP_RESERVE) ||
|
|
||||||
reserveIds[i] == kyberStorage.getReserveId(KYBER_UNISWAPV2_RESERVE) ||
|
|
||||||
reserveIds[i] == kyberStorage.getReserveId(KYBER_ETH2DAI_RESERVE)
|
|
||||||
) {
|
|
||||||
bannedReserveIds = _appendToList(bannedReserveIds, reserveIds[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sampler either detects X->ETH/ETH->X
|
|
||||||
// or subsamples as X->ETH-Y. So token->token here is not possible
|
|
||||||
bytes memory hint;
|
|
||||||
if (takerToken == _getWethAddress()) {
|
|
||||||
// ETH -> X
|
|
||||||
hint = kyberHint.buildEthToTokenHint(
|
|
||||||
makerToken,
|
|
||||||
IKyberHintHandler.TradeType.MaskOut,
|
|
||||||
bannedReserveIds,
|
|
||||||
new uint256[](0));
|
|
||||||
} else {
|
|
||||||
// X->ETH
|
|
||||||
hint = kyberHint.buildEthToTokenHint(
|
|
||||||
takerToken,
|
|
||||||
IKyberHintHandler.TradeType.MaskOut,
|
|
||||||
bannedReserveIds,
|
|
||||||
new uint256[](0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(bool didSucceed, bytes memory resultData) =
|
(bool didSucceed, bytes memory resultData) =
|
||||||
_getKyberNetworkProxyAddress().staticcall.gas(KYBER_CALL_GAS)(
|
_getKyberNetworkProxyAddress().staticcall.gas(KYBER_CALL_GAS)(
|
||||||
abi.encodeWithSelector(
|
abi.encodeWithSelector(
|
||||||
|
@ -1,52 +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.5.9;
|
|
||||||
|
|
||||||
|
|
||||||
interface IKyberHintHandler {
|
|
||||||
|
|
||||||
function kyberStorage() external returns (address);
|
|
||||||
|
|
||||||
enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
|
|
||||||
|
|
||||||
function buildTokenToEthHint(
|
|
||||||
address tokenSrc,
|
|
||||||
TradeType tokenToEthType,
|
|
||||||
bytes32[] calldata tokenToEthReserveIds,
|
|
||||||
uint256[] calldata tokenToEthSplits
|
|
||||||
) external view returns (bytes memory hint);
|
|
||||||
|
|
||||||
function buildEthToTokenHint(
|
|
||||||
address tokenDest,
|
|
||||||
TradeType ethToTokenType,
|
|
||||||
bytes32[] calldata ethToTokenReserveIds,
|
|
||||||
uint256[] calldata ethToTokenSplits
|
|
||||||
) external view returns (bytes memory hint);
|
|
||||||
|
|
||||||
function buildTokenToTokenHint(
|
|
||||||
address tokenSrc,
|
|
||||||
TradeType tokenToEthType,
|
|
||||||
bytes32[] calldata tokenToEthReserveIds,
|
|
||||||
uint256[] calldata tokenToEthSplits,
|
|
||||||
address tokenDest,
|
|
||||||
TradeType ethToTokenType,
|
|
||||||
bytes32[] calldata ethToTokenReserveIds,
|
|
||||||
uint256[] calldata ethToTokenSplits
|
|
||||||
) external view returns (bytes memory hint);
|
|
||||||
}
|
|
@ -18,20 +18,62 @@
|
|||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
import "./IKyberStorage.sol";
|
// Keepin everything together
|
||||||
import "./IKyberHintHandler.sol";
|
|
||||||
|
|
||||||
|
|
||||||
interface IKyberNetwork {
|
interface IKyberNetwork {
|
||||||
|
|
||||||
function getContracts()
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface IKyberNetworkProxy {
|
||||||
|
|
||||||
|
function getExpectedRateAfterFee(
|
||||||
|
address src,
|
||||||
|
address dest,
|
||||||
|
uint256 srcQty,
|
||||||
|
uint256 platformFeeBps,
|
||||||
|
bytes calldata hint
|
||||||
|
)
|
||||||
external
|
external
|
||||||
view
|
view
|
||||||
returns (
|
returns (uint256 expectedRate);
|
||||||
address kyberFeeHandlerAddress,
|
}
|
||||||
address kyberDaoAddress,
|
|
||||||
IKyberHintHandler kyberMatchingEngineAddress,
|
interface IKyberHintHandler {
|
||||||
IKyberStorage kyberStorageAddress,
|
|
||||||
address gasHelperAddress,
|
enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
|
||||||
address[] memory kyberProxyAddresses);
|
|
||||||
|
function buildTokenToEthHint(
|
||||||
|
address tokenSrc,
|
||||||
|
TradeType tokenToEthType,
|
||||||
|
bytes32[] calldata tokenToEthReserveIds,
|
||||||
|
uint256[] calldata tokenToEthSplits
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes memory hint);
|
||||||
|
|
||||||
|
function buildEthToTokenHint(
|
||||||
|
address tokenDest,
|
||||||
|
TradeType ethToTokenType,
|
||||||
|
bytes32[] calldata ethToTokenReserveIds,
|
||||||
|
uint256[] calldata ethToTokenSplits
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes memory hint);
|
||||||
|
|
||||||
|
function buildTokenToTokenHint(
|
||||||
|
address tokenSrc,
|
||||||
|
TradeType tokenToEthType,
|
||||||
|
bytes32[] calldata tokenToEthReserveIds,
|
||||||
|
uint256[] calldata tokenToEthSplits,
|
||||||
|
address tokenDest,
|
||||||
|
TradeType ethToTokenType,
|
||||||
|
bytes32[] calldata ethToTokenReserveIds,
|
||||||
|
uint256[] calldata ethToTokenSplits
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes memory hint);
|
||||||
}
|
}
|
||||||
|
@ -1,34 +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.5.9;
|
|
||||||
|
|
||||||
|
|
||||||
interface IKyberNetworkProxy {
|
|
||||||
|
|
||||||
function kyberNetwork() external view returns (address);
|
|
||||||
function kyberHintHandler() external view returns (address);
|
|
||||||
|
|
||||||
function getExpectedRateAfterFee(
|
|
||||||
address src,
|
|
||||||
address dest,
|
|
||||||
uint256 srcQty,
|
|
||||||
uint256 platformFeeBps,
|
|
||||||
bytes calldata hint
|
|
||||||
) external view returns (uint256 expectedRate);
|
|
||||||
}
|
|
@ -1,37 +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.5.9;
|
|
||||||
|
|
||||||
|
|
||||||
interface IKyberStorage {
|
|
||||||
|
|
||||||
function getReserveId(
|
|
||||||
address reserve
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (bytes32 reserveId);
|
|
||||||
|
|
||||||
function getReserveIdsPerTokenSrc(
|
|
||||||
address token
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (bytes32[] memory reserveIds);
|
|
||||||
}
|
|
@ -23,7 +23,7 @@ import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
|||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
import "../src/ERC20BridgeSampler.sol";
|
import "../src/ERC20BridgeSampler.sol";
|
||||||
import "../src/interfaces/IEth2Dai.sol";
|
import "../src/interfaces/IEth2Dai.sol";
|
||||||
import "../src/interfaces/IKyberNetworkProxy.sol";
|
import "../src/interfaces/IKyberNetwork.sol";
|
||||||
import "../src/interfaces/IUniswapV2Router01.sol";
|
import "../src/interfaces/IUniswapV2Router01.sol";
|
||||||
|
|
||||||
|
|
||||||
@ -253,76 +253,40 @@ contract TestERC20BridgeSamplerKyberNetwork is
|
|||||||
|
|
||||||
enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
|
enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
|
||||||
|
|
||||||
function kyberNetwork()
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address)
|
|
||||||
{
|
|
||||||
return address(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IKyberNetwork
|
|
||||||
function getContracts()
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (
|
|
||||||
address kyberFeeHandlerAddress,
|
|
||||||
address kyberDaoAddress,
|
|
||||||
address kyberMatchingEngineAddress,
|
|
||||||
address kyberStorageAddress,
|
|
||||||
address gasHelperAddress,
|
|
||||||
address[] memory kyberProxyAddresses
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return (kyberFeeHandlerAddress,
|
|
||||||
kyberDaoAddress,
|
|
||||||
address(this),
|
|
||||||
address(this),
|
|
||||||
gasHelperAddress,
|
|
||||||
kyberProxyAddresses
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IKyberStorage
|
|
||||||
function getReserveIdsPerTokenSrc(
|
|
||||||
address /* token */
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (bytes32[] memory reserveIds)
|
|
||||||
{
|
|
||||||
return reserveIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getReserveId(
|
|
||||||
address /* reserve */
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (bytes32 reserveId)
|
|
||||||
{
|
|
||||||
return reserveId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IKyberHintHandler
|
// IKyberHintHandler
|
||||||
function buildTokenToEthHint(
|
function buildTokenToEthHint(
|
||||||
address /* tokenSrc */,
|
address tokenSrc,
|
||||||
TradeType /* tokenToEthType */,
|
TradeType /* tokenToEthType */,
|
||||||
bytes32[] calldata /* tokenToEthReserveIds */,
|
bytes32[] calldata /* tokenToEthReserveIds */,
|
||||||
uint256[] calldata /* tokenToEthSplits */
|
uint256[] calldata /* tokenToEthSplits */
|
||||||
) external view returns (bytes memory hint)
|
) external view returns (bytes memory hint)
|
||||||
{
|
{
|
||||||
return hint;
|
return abi.encode(tokenSrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEthToTokenHint(
|
function buildEthToTokenHint(
|
||||||
address /* tokenDest */,
|
address tokenDest,
|
||||||
TradeType /* ethToTokenType */,
|
TradeType /* ethToTokenType */,
|
||||||
bytes32[] calldata /* ethToTokenReserveIds */,
|
bytes32[] calldata /* ethToTokenReserveIds */,
|
||||||
uint256[] calldata /* ethToTokenSplits */
|
uint256[] calldata /* ethToTokenSplits */
|
||||||
) external view returns (bytes memory hint)
|
) external view returns (bytes memory hint)
|
||||||
{
|
{
|
||||||
return hint;
|
return abi.encode(tokenDest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IKyberHintHandler
|
||||||
|
function buildTokenToTokenHint(
|
||||||
|
address tokenSrc,
|
||||||
|
TradeType /* tokenToEthType */,
|
||||||
|
bytes32[] calldata /* tokenToEthReserveIds */,
|
||||||
|
uint256[] calldata /* tokenToEthSplits */,
|
||||||
|
address /* tokenDest */,
|
||||||
|
TradeType /* EthToTokenType */,
|
||||||
|
bytes32[] calldata /* EthToTokenReserveIds */,
|
||||||
|
uint256[] calldata /* EthToTokenSplits */
|
||||||
|
) external view returns (bytes memory hint)
|
||||||
|
{
|
||||||
|
return abi.encode(tokenSrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deterministic `IKyberNetworkProxy.getExpectedRateAfterFee()`.
|
// Deterministic `IKyberNetworkProxy.getExpectedRateAfterFee()`.
|
||||||
@ -375,6 +339,14 @@ contract TestERC20BridgeSamplerKyberNetwork is
|
|||||||
{
|
{
|
||||||
return address(this);
|
return address(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _getKyberHintHandlerAddress()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (address)
|
||||||
|
{
|
||||||
|
return address(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -533,4 +505,13 @@ contract TestERC20BridgeSampler is
|
|||||||
{
|
{
|
||||||
return address(kyber);
|
return address(kyber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overriden to point to a custom contract.
|
||||||
|
function _getKyberHintHandlerAddress()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (address kyberAddress)
|
||||||
|
{
|
||||||
|
return address(kyber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
"publicInterfaceContracts": "ERC20BridgeSampler,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/@(ApproximateBuys|BalancerSampler|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberHintHandler|IKyberNetwork|IKyberNetworkProxy|IKyberStorage|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
||||||
"postpublish": {
|
"postpublish": {
|
||||||
"assets": []
|
"assets": []
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,8 @@ export {
|
|||||||
SamplerContractOperation,
|
SamplerContractOperation,
|
||||||
} from './utils/market_operation_utils/sampler_contract_operation';
|
} from './utils/market_operation_utils/sampler_contract_operation';
|
||||||
export {
|
export {
|
||||||
BancorFillData,
|
|
||||||
BalancerFillData,
|
BalancerFillData,
|
||||||
|
BancorFillData,
|
||||||
CollapsedFill,
|
CollapsedFill,
|
||||||
CurveFillData,
|
CurveFillData,
|
||||||
CurveFunctionSelectors,
|
CurveFunctionSelectors,
|
||||||
@ -135,6 +135,7 @@ export {
|
|||||||
FillData,
|
FillData,
|
||||||
FillFlags,
|
FillFlags,
|
||||||
GetMarketOrdersRfqtOpts,
|
GetMarketOrdersRfqtOpts,
|
||||||
|
KyberFillData,
|
||||||
LiquidityProviderFillData,
|
LiquidityProviderFillData,
|
||||||
MarketDepth,
|
MarketDepth,
|
||||||
MarketDepthSide,
|
MarketDepthSide,
|
||||||
|
@ -132,6 +132,42 @@ export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MAINNET_KYBER_RESERVE_IDS: { [name: string]: string } = {
|
||||||
|
Reserve1: '0xff4b796265722046707200000000000000000000000000000000000000000000',
|
||||||
|
Reserve2: '0xffabcd0000000000000000000000000000000000000000000000000000000000',
|
||||||
|
Reserve3: '0xff4f6e65426974205175616e7400000000000000000000000000000000000000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MAINNET_KYBER_TOKEN_RESERVE_IDS: { [token: string]: string } = {
|
||||||
|
// USDC
|
||||||
|
['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48']:
|
||||||
|
'0xaa55534443303041505200000000000000000000000000000000000000000000',
|
||||||
|
// AMPL
|
||||||
|
['0xd46ba6d942050d489dbd938a2c909a5d5039a161']:
|
||||||
|
'0xaad46ba6d942050d489dbd938a2c909a5d5039a1610000000000000000000000',
|
||||||
|
// UBT
|
||||||
|
['0x8400d94a5cb0fa0d041a3788e395285d61c9ee5e']:
|
||||||
|
'0xaa55425400000000000000000000000000000000000000000000000000000000',
|
||||||
|
// ANT
|
||||||
|
['0x960b236a07cf122663c4303350609a66a7b288c0']:
|
||||||
|
'0xaa414e5400000000000000000000000000000000000000000000000000000000',
|
||||||
|
// KNC
|
||||||
|
['0xdd974d5c2e2928dea5f71b9825b8b646686bd200']:
|
||||||
|
'0xaa4b4e435f4d4547414c41444f4e000000000000000000000000000000000000',
|
||||||
|
// sUSD
|
||||||
|
['0x57ab1ec28d129707052df4df418d58a2d46d5f51']:
|
||||||
|
'0xaa73555344000000000000000000000000000000000000000000000000000000',
|
||||||
|
// SNX
|
||||||
|
['0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f']:
|
||||||
|
'0xaa534e5800000000000000000000000000000000000000000000000000000000',
|
||||||
|
// REN
|
||||||
|
['0x408e41876cccdc0f92210600ef50372656052a38']:
|
||||||
|
'0xaa72656e00000000000000000000000000000000000000000000000000000000',
|
||||||
|
// BAND
|
||||||
|
['0xba11d00c5f74255f56a5e366f4f77f5a186d7f55']:
|
||||||
|
'0xaa42414e44000000000000000000000000000000000000000000000000000000',
|
||||||
|
};
|
||||||
|
|
||||||
export const ERC20_PROXY_ID = '0xf47261b0';
|
export const ERC20_PROXY_ID = '0xf47261b0';
|
||||||
export const WALLET_SIGNATURE = '0x04';
|
export const WALLET_SIGNATURE = '0x04';
|
||||||
export const ONE_ETHER = new BigNumber(1e18);
|
export const ONE_ETHER = new BigNumber(1e18);
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
import { MAINNET_KYBER_RESERVE_IDS, MAINNET_KYBER_TOKEN_RESERVE_IDS } from './constants';
|
||||||
|
|
||||||
|
// tslint:disable completed-docs
|
||||||
|
export function getKyberReserveIdsForPair(takerToken: string, makerToken: string): string[] {
|
||||||
|
return [
|
||||||
|
...Object.values(MAINNET_KYBER_RESERVE_IDS),
|
||||||
|
MAINNET_KYBER_TOKEN_RESERVE_IDS[makerToken.toLowerCase()],
|
||||||
|
MAINNET_KYBER_TOKEN_RESERVE_IDS[takerToken.toLowerCase()],
|
||||||
|
].filter(t => t);
|
||||||
|
}
|
@ -27,6 +27,7 @@ import {
|
|||||||
DexSample,
|
DexSample,
|
||||||
ERC20BridgeSource,
|
ERC20BridgeSource,
|
||||||
Fill,
|
Fill,
|
||||||
|
KyberFillData,
|
||||||
LiquidityProviderFillData,
|
LiquidityProviderFillData,
|
||||||
MultiBridgeFillData,
|
MultiBridgeFillData,
|
||||||
MultiHopFillData,
|
MultiHopFillData,
|
||||||
@ -295,6 +296,14 @@ function createBridgeOrder(
|
|||||||
createMultiBridgeData(takerToken, makerToken),
|
createMultiBridgeData(takerToken, makerToken),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case ERC20BridgeSource.Kyber:
|
||||||
|
const kyberFillData = (fill as CollapsedFill<KyberFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
|
||||||
|
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||||
|
makerToken,
|
||||||
|
bridgeAddress,
|
||||||
|
createKyberBridgeData(takerToken, kyberFillData.hint),
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||||
makerToken,
|
makerToken,
|
||||||
@ -393,6 +402,11 @@ function createBancorBridgeData(path: string[], networkAddress: string): string
|
|||||||
return encoder.encode({ path, networkAddress });
|
return encoder.encode({ path, networkAddress });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createKyberBridgeData(fromTokenAddress: string, hint: string): string {
|
||||||
|
const encoder = AbiEncoder.create([{ name: 'fromTokenAddress', type: 'address' }, { name: 'hint', type: 'bytes' }]);
|
||||||
|
return encoder.encode({ fromTokenAddress, hint });
|
||||||
|
}
|
||||||
|
|
||||||
function createCurveBridgeData(
|
function createCurveBridgeData(
|
||||||
curveAddress: string,
|
curveAddress: string,
|
||||||
exchangeFunctionSelector: string,
|
exchangeFunctionSelector: string,
|
||||||
|
@ -8,6 +8,7 @@ import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote }
|
|||||||
import { BancorService } from './bancor_service';
|
import { BancorService } from './bancor_service';
|
||||||
import { MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants';
|
import { MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants';
|
||||||
import { getCurveInfosForPair } from './curve_utils';
|
import { getCurveInfosForPair } from './curve_utils';
|
||||||
|
import { getKyberReserveIdsForPair } from './kyber_utils';
|
||||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
||||||
import { getIntermediateTokens } from './multihop_utils';
|
import { getIntermediateTokens } from './multihop_utils';
|
||||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||||
@ -20,6 +21,7 @@ import {
|
|||||||
DexSample,
|
DexSample,
|
||||||
ERC20BridgeSource,
|
ERC20BridgeSource,
|
||||||
HopInfo,
|
HopInfo,
|
||||||
|
KyberFillData,
|
||||||
LiquidityProviderFillData,
|
LiquidityProviderFillData,
|
||||||
MultiBridgeFillData,
|
MultiBridgeFillData,
|
||||||
MultiHopFillData,
|
MultiHopFillData,
|
||||||
@ -71,6 +73,7 @@ export class SamplerOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getKyberSellQuotes(
|
public getKyberSellQuotes(
|
||||||
|
reserveId: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
takerFillAmounts: BigNumber[],
|
takerFillAmounts: BigNumber[],
|
||||||
@ -79,11 +82,21 @@ export class SamplerOperations {
|
|||||||
source: ERC20BridgeSource.Kyber,
|
source: ERC20BridgeSource.Kyber,
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleSellsFromKyberNetwork,
|
function: this._samplerContract.sampleSellsFromKyberNetwork,
|
||||||
params: [takerToken, makerToken, takerFillAmounts],
|
params: [reserveId, takerToken, makerToken, takerFillAmounts],
|
||||||
|
callback: (callResults: string, fillData: KyberFillData): BigNumber[] => {
|
||||||
|
const [hint, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
|
||||||
|
'sampleSellsFromKyberNetwork',
|
||||||
|
callResults,
|
||||||
|
);
|
||||||
|
fillData.hint = hint;
|
||||||
|
fillData.reserveId = reserveId;
|
||||||
|
return samples;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getKyberBuyQuotes(
|
public getKyberBuyQuotes(
|
||||||
|
reserveId: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerFillAmounts: BigNumber[],
|
makerFillAmounts: BigNumber[],
|
||||||
@ -92,7 +105,16 @@ export class SamplerOperations {
|
|||||||
source: ERC20BridgeSource.Kyber,
|
source: ERC20BridgeSource.Kyber,
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleBuysFromKyberNetwork,
|
function: this._samplerContract.sampleBuysFromKyberNetwork,
|
||||||
params: [takerToken, makerToken, makerFillAmounts],
|
params: [reserveId, takerToken, makerToken, makerFillAmounts],
|
||||||
|
callback: (callResults: string, fillData: KyberFillData): BigNumber[] => {
|
||||||
|
const [hint, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
|
||||||
|
'sampleBuysFromKyberNetwork',
|
||||||
|
callResults,
|
||||||
|
);
|
||||||
|
fillData.hint = hint;
|
||||||
|
fillData.reserveId = reserveId;
|
||||||
|
return samples;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,7 +768,9 @@ export class SamplerOperations {
|
|||||||
}
|
}
|
||||||
return ops;
|
return ops;
|
||||||
case ERC20BridgeSource.Kyber:
|
case ERC20BridgeSource.Kyber:
|
||||||
return this.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts);
|
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>
|
||||||
|
this.getKyberSellQuotes(reserveId, makerToken, takerToken, takerFillAmounts),
|
||||||
|
);
|
||||||
case ERC20BridgeSource.Curve:
|
case ERC20BridgeSource.Curve:
|
||||||
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
||||||
this.getCurveSellQuotes(
|
this.getCurveSellQuotes(
|
||||||
@ -825,7 +849,9 @@ export class SamplerOperations {
|
|||||||
}
|
}
|
||||||
return ops;
|
return ops;
|
||||||
case ERC20BridgeSource.Kyber:
|
case ERC20BridgeSource.Kyber:
|
||||||
return this.getKyberBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>
|
||||||
|
this.getKyberBuyQuotes(reserveId, makerToken, takerToken, makerFillAmounts),
|
||||||
|
);
|
||||||
case ERC20BridgeSource.Curve:
|
case ERC20BridgeSource.Curve:
|
||||||
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
||||||
this.getCurveBuyQuotes(
|
this.getCurveBuyQuotes(
|
||||||
|
@ -108,6 +108,11 @@ export interface BancorFillData extends FillData {
|
|||||||
networkAddress: string;
|
networkAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface KyberFillData extends FillData {
|
||||||
|
hint: string;
|
||||||
|
reserveId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Quote<TFillData = FillData> {
|
export interface Quote<TFillData = FillData> {
|
||||||
amount: BigNumber;
|
amount: BigNumber;
|
||||||
fillData?: TFillData;
|
fillData?: TFillData;
|
||||||
|
@ -15,10 +15,7 @@ import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json
|
|||||||
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
||||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||||
import * as IKyberHintHandler from '../test/generated-artifacts/IKyberHintHandler.json';
|
|
||||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||||
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
|
|
||||||
import * as IKyberStorage from '../test/generated-artifacts/IKyberStorage.json';
|
|
||||||
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 IMooniswap from '../test/generated-artifacts/IMooniswap.json';
|
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
|
||||||
@ -58,10 +55,7 @@ export const artifacts = {
|
|||||||
IBalancer: IBalancer as ContractArtifact,
|
IBalancer: IBalancer as ContractArtifact,
|
||||||
ICurve: ICurve as ContractArtifact,
|
ICurve: ICurve as ContractArtifact,
|
||||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||||
IKyberHintHandler: IKyberHintHandler as ContractArtifact,
|
|
||||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||||
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
|
|
||||||
IKyberStorage: IKyberStorage as ContractArtifact,
|
|
||||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
||||||
IMStable: IMStable as ContractArtifact,
|
IMStable: IMStable as ContractArtifact,
|
||||||
|
@ -81,24 +81,25 @@ blockchainTests.skip('Mainnet Sampler Tests', env => {
|
|||||||
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||||
const DAI = '0x6b175474e89094c44da98b954eedeac495271d0f';
|
const DAI = '0x6b175474e89094c44da98b954eedeac495271d0f';
|
||||||
const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
|
const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
|
||||||
|
const RESERVE_ID = '0xff4b796265722046707200000000000000000000000000000000000000000000';
|
||||||
describe('sampleSellsFromKyberNetwork()', () => {
|
describe('sampleSellsFromKyberNetwork()', () => {
|
||||||
it('samples sells from Kyber DAI->WETH', async () => {
|
it('samples sells from Kyber DAI->WETH', async () => {
|
||||||
const samples = await testContract
|
const [, samples] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(DAI, WETH, [toBaseUnitAmount(1)])
|
.sampleSellsFromKyberNetwork(RESERVE_ID, DAI, WETH, [toBaseUnitAmount(1)])
|
||||||
.callAsync({ overrides });
|
.callAsync({ overrides });
|
||||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||||
});
|
});
|
||||||
it('samples sells from Kyber WETH->DAI', async () => {
|
it('samples sells from Kyber WETH->DAI', async () => {
|
||||||
const samples = await testContract
|
const [, samples] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(WETH, DAI, [toBaseUnitAmount(1)])
|
.sampleSellsFromKyberNetwork(RESERVE_ID, WETH, DAI, [toBaseUnitAmount(1)])
|
||||||
.callAsync({ overrides });
|
.callAsync({ overrides });
|
||||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||||
});
|
});
|
||||||
it('samples sells from Kyber DAI->USDC', async () => {
|
it('samples sells from Kyber DAI->USDC', async () => {
|
||||||
const samples = await testContract
|
const [, samples] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(DAI, USDC, [toBaseUnitAmount(1)])
|
.sampleSellsFromKyberNetwork(RESERVE_ID, DAI, USDC, [toBaseUnitAmount(1)])
|
||||||
.callAsync({ overrides });
|
.callAsync({ overrides });
|
||||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||||
@ -109,8 +110,8 @@ blockchainTests.skip('Mainnet Sampler Tests', env => {
|
|||||||
it('samples buys from Kyber WETH->DAI', async () => {
|
it('samples buys from Kyber WETH->DAI', async () => {
|
||||||
// From ETH to DAI
|
// From ETH to DAI
|
||||||
// I want to buy 1 DAI
|
// I want to buy 1 DAI
|
||||||
const samples = await testContract
|
const [, samples] = await testContract
|
||||||
.sampleBuysFromKyberNetwork(WETH, DAI, [toBaseUnitAmount(1)])
|
.sampleBuysFromKyberNetwork(RESERVE_ID, WETH, DAI, [toBaseUnitAmount(1)])
|
||||||
.callAsync({ overrides });
|
.callAsync({ overrides });
|
||||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||||
@ -119,8 +120,8 @@ blockchainTests.skip('Mainnet Sampler Tests', env => {
|
|||||||
it('samples buys from Kyber DAI->WETH', async () => {
|
it('samples buys from Kyber DAI->WETH', async () => {
|
||||||
// From USDC to DAI
|
// From USDC to DAI
|
||||||
// I want to buy 1 WETH
|
// I want to buy 1 WETH
|
||||||
const samples = await testContract
|
const [, samples] = await testContract
|
||||||
.sampleBuysFromKyberNetwork(DAI, WETH, [toBaseUnitAmount(1)])
|
.sampleBuysFromKyberNetwork(RESERVE_ID, DAI, WETH, [toBaseUnitAmount(1)])
|
||||||
.callAsync({ overrides });
|
.callAsync({ overrides });
|
||||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||||
|
@ -38,6 +38,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const MAKER_TOKEN = randomAddress();
|
const MAKER_TOKEN = randomAddress();
|
||||||
const TAKER_TOKEN = randomAddress();
|
const TAKER_TOKEN = randomAddress();
|
||||||
const INTERMEDIATE_TOKEN = randomAddress();
|
const INTERMEDIATE_TOKEN = randomAddress();
|
||||||
|
const KYBER_RESERVE_ID = '0x';
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
testContract = await TestERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
|
testContract = await TestERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
|
||||||
@ -330,31 +331,25 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('throws if tokens are the same', async () => {
|
it('throws if tokens are the same', async () => {
|
||||||
const tx = testContract.sampleSellsFromKyberNetwork(MAKER_TOKEN, MAKER_TOKEN, []).callAsync();
|
const tx = testContract
|
||||||
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, MAKER_TOKEN, MAKER_TOKEN, [])
|
||||||
|
.callAsync();
|
||||||
return expect(tx).to.revertWith(INVALID_TOKEN_PAIR_ERROR);
|
return expect(tx).to.revertWith(INVALID_TOKEN_PAIR_ERROR);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can return no quotes', async () => {
|
it('can return no quotes', async () => {
|
||||||
const quotes = await testContract.sampleSellsFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, []).callAsync();
|
const [, quotes] = await testContract
|
||||||
expect(quotes).to.deep.eq([]);
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, [])
|
||||||
});
|
|
||||||
|
|
||||||
it('can quote token -> token', async () => {
|
|
||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
|
||||||
const [takerToEthQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
|
||||||
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, MAKER_TOKEN, ['Kyber'], takerToEthQuotes);
|
|
||||||
const quotes = await testContract
|
|
||||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns zero if token -> token fails', async () => {
|
it('returns zero if token -> token fails', async () => {
|
||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
await enableFailTriggerAsync();
|
await enableFailTriggerAsync();
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@ -362,8 +357,17 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('can quote token -> ETH', async () => {
|
it('can quote token -> ETH', async () => {
|
||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||||
|
.callAsync();
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can quote token -> token', async () => {
|
||||||
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
|
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||||
|
const [, quotes] = await testContract
|
||||||
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@ -372,8 +376,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
await enableFailTriggerAsync();
|
await enableFailTriggerAsync();
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@ -381,8 +385,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('can quote ETH -> token', async () => {
|
it('can quote ETH -> token', async () => {
|
||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
|
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@ -391,8 +395,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
await enableFailTriggerAsync();
|
await enableFailTriggerAsync();
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleSellsFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@ -405,21 +409,24 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('throws if tokens are the same', async () => {
|
it('throws if tokens are the same', async () => {
|
||||||
const tx = testContract.sampleBuysFromKyberNetwork(MAKER_TOKEN, MAKER_TOKEN, []).callAsync();
|
const tx = testContract
|
||||||
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, MAKER_TOKEN, MAKER_TOKEN, [])
|
||||||
|
.callAsync();
|
||||||
return expect(tx).to.revertWith(INVALID_TOKEN_PAIR_ERROR);
|
return expect(tx).to.revertWith(INVALID_TOKEN_PAIR_ERROR);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can return no quotes', async () => {
|
it('can return no quotes', async () => {
|
||||||
const quotes = await testContract.sampleBuysFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, []).callAsync();
|
const [, quotes] = await testContract
|
||||||
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, [])
|
||||||
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq([]);
|
expect(quotes).to.deep.eq([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can quote token -> token', async () => {
|
it('can quote token -> token', async () => {
|
||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const [ethToMakerQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, MAKER_TOKEN, ['Kyber'], sampleAmounts);
|
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], ethToMakerQuotes);
|
const [, quotes] = await testContract
|
||||||
const quotes = await testContract
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
||||||
});
|
});
|
||||||
@ -428,8 +435,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
await enableFailTriggerAsync();
|
await enableFailTriggerAsync();
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@ -437,8 +444,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('can quote token -> ETH', async () => {
|
it('can quote token -> ETH', async () => {
|
||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
||||||
});
|
});
|
||||||
@ -447,8 +454,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
await enableFailTriggerAsync();
|
await enableFailTriggerAsync();
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@ -456,8 +463,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('can quote ETH -> token', async () => {
|
it('can quote ETH -> token', async () => {
|
||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
|
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleBuysFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
||||||
});
|
});
|
||||||
@ -466,8 +473,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||||
await enableFailTriggerAsync();
|
await enableFailTriggerAsync();
|
||||||
const quotes = await testContract
|
const [, quotes] = await testContract
|
||||||
.sampleBuysFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
|
@ -135,16 +135,21 @@ describe('DexSampler tests', () => {
|
|||||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||||
const sampler = new MockSamplerContract({
|
const sampler = new MockSamplerContract({
|
||||||
sampleSellsFromKyberNetwork: (takerToken, makerToken, fillAmounts) => {
|
sampleSellsFromKyberNetwork: (_reserveId, takerToken, makerToken, fillAmounts) => {
|
||||||
expect(takerToken).to.eq(expectedTakerToken);
|
expect(takerToken).to.eq(expectedTakerToken);
|
||||||
expect(makerToken).to.eq(expectedMakerToken);
|
expect(makerToken).to.eq(expectedMakerToken);
|
||||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||||
return expectedMakerFillAmounts;
|
return ['0x', expectedMakerFillAmounts];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||||
dexOrderSampler.getKyberSellQuotes(expectedMakerToken, expectedTakerToken, expectedTakerFillAmounts),
|
dexOrderSampler.getKyberSellQuotes(
|
||||||
|
'0x',
|
||||||
|
expectedMakerToken,
|
||||||
|
expectedTakerToken,
|
||||||
|
expectedTakerFillAmounts,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||||
});
|
});
|
||||||
@ -373,12 +378,7 @@ describe('DexSampler tests', () => {
|
|||||||
it('getSellQuotes()', async () => {
|
it('getSellQuotes()', async () => {
|
||||||
const expectedTakerToken = randomAddress();
|
const expectedTakerToken = randomAddress();
|
||||||
const expectedMakerToken = randomAddress();
|
const expectedMakerToken = randomAddress();
|
||||||
const sources = [
|
const sources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
|
||||||
ERC20BridgeSource.Kyber,
|
|
||||||
ERC20BridgeSource.Eth2Dai,
|
|
||||||
ERC20BridgeSource.Uniswap,
|
|
||||||
ERC20BridgeSource.UniswapV2,
|
|
||||||
];
|
|
||||||
const ratesBySource: RatesBySource = {
|
const ratesBySource: RatesBySource = {
|
||||||
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
|
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
|
||||||
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
||||||
@ -387,12 +387,6 @@ describe('DexSampler tests', () => {
|
|||||||
};
|
};
|
||||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||||
const sampler = new MockSamplerContract({
|
const sampler = new MockSamplerContract({
|
||||||
sampleSellsFromKyberNetwork: (takerToken, makerToken, fillAmounts) => {
|
|
||||||
expect(takerToken).to.eq(expectedTakerToken);
|
|
||||||
expect(makerToken).to.eq(expectedMakerToken);
|
|
||||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
|
||||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Kyber]).integerValue());
|
|
||||||
},
|
|
||||||
sampleSellsFromUniswap: (takerToken, makerToken, fillAmounts) => {
|
sampleSellsFromUniswap: (takerToken, makerToken, fillAmounts) => {
|
||||||
expect(takerToken).to.eq(expectedTakerToken);
|
expect(takerToken).to.eq(expectedTakerToken);
|
||||||
expect(makerToken).to.eq(expectedMakerToken);
|
expect(makerToken).to.eq(expectedMakerToken);
|
||||||
@ -449,7 +443,8 @@ describe('DexSampler tests', () => {
|
|||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
// extra quote for Uniswap V2, which provides a direct quote (tokenA -> tokenB) AND an ETH quote (tokenA -> ETH -> tokenB)
|
// extra quote for Uniswap V2, which provides a direct quote (tokenA -> tokenB) AND an ETH quote (tokenA -> ETH -> tokenB)
|
||||||
expect(quotes).to.have.lengthOf(sources.length + 1);
|
const additionalSourceCount = 1;
|
||||||
|
expect(quotes).to.have.lengthOf(sources.length + additionalSourceCount);
|
||||||
expect(quotes).to.deep.eq(expectedQuotes.concat(uniswapV2ETHQuotes));
|
expect(quotes).to.deep.eq(expectedQuotes.concat(uniswapV2ETHQuotes));
|
||||||
});
|
});
|
||||||
it('getSellQuotes() uses samples from Balancer', async () => {
|
it('getSellQuotes() uses samples from Balancer', async () => {
|
||||||
|
@ -261,6 +261,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.UniswapV2]: { tokenAddressPath: [] },
|
[ERC20BridgeSource.UniswapV2]: { tokenAddressPath: [] },
|
||||||
[ERC20BridgeSource.Balancer]: { poolAddress: randomAddress() },
|
[ERC20BridgeSource.Balancer]: { poolAddress: randomAddress() },
|
||||||
[ERC20BridgeSource.Bancor]: { path: [], networkAddress: randomAddress() },
|
[ERC20BridgeSource.Bancor]: { path: [], networkAddress: randomAddress() },
|
||||||
|
[ERC20BridgeSource.Kyber]: { hint: '0x', reserveId: '0x' },
|
||||||
[ERC20BridgeSource.Curve]: {
|
[ERC20BridgeSource.Curve]: {
|
||||||
curve: {
|
curve: {
|
||||||
poolAddress: randomAddress(),
|
poolAddress: randomAddress(),
|
||||||
|
@ -23,6 +23,18 @@ export type SampleBuysHandler = (
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
makerTokenAmounts: BigNumber[],
|
makerTokenAmounts: BigNumber[],
|
||||||
) => SampleResults;
|
) => SampleResults;
|
||||||
|
export type SampleSellsKyberHandler = (
|
||||||
|
reserveId: string,
|
||||||
|
takerToken: string,
|
||||||
|
makerToken: string,
|
||||||
|
takerTokenAmounts: BigNumber[],
|
||||||
|
) => [string, SampleResults];
|
||||||
|
export type SampleBuysKyberHandler = (
|
||||||
|
reserveId: string,
|
||||||
|
takerToken: string,
|
||||||
|
makerToken: string,
|
||||||
|
makerTokenAmounts: BigNumber[],
|
||||||
|
) => [string, SampleResults];
|
||||||
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
||||||
export type SampleSellsLPHandler = (
|
export type SampleSellsLPHandler = (
|
||||||
registryAddress: string,
|
registryAddress: string,
|
||||||
@ -48,7 +60,7 @@ const DUMMY_PROVIDER = {
|
|||||||
interface Handlers {
|
interface Handlers {
|
||||||
getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||||
getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||||
sampleSellsFromKyberNetwork: SampleSellsHandler;
|
sampleSellsFromKyberNetwork: SampleSellsKyberHandler;
|
||||||
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
||||||
sampleSellsFromMultiBridge: SampleSellsMBHandler;
|
sampleSellsFromMultiBridge: SampleSellsMBHandler;
|
||||||
sampleSellsFromEth2Dai: SampleSellsHandler;
|
sampleSellsFromEth2Dai: SampleSellsHandler;
|
||||||
@ -104,13 +116,15 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public sampleSellsFromKyberNetwork(
|
public sampleSellsFromKyberNetwork(
|
||||||
|
reserveId: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerAssetAmounts: BigNumber[],
|
takerAssetAmounts: BigNumber[],
|
||||||
): ContractFunctionObj<BigNumber[]> {
|
): ContractFunctionObj<[string, BigNumber[]]> {
|
||||||
return this._wrapCall(
|
return this._wrapCall(
|
||||||
super.sampleSellsFromKyberNetwork,
|
super.sampleSellsFromKyberNetwork,
|
||||||
this._handlers.sampleSellsFromKyberNetwork,
|
this._handlers.sampleSellsFromKyberNetwork,
|
||||||
|
reserveId,
|
||||||
takerToken,
|
takerToken,
|
||||||
makerToken,
|
makerToken,
|
||||||
takerAssetAmounts,
|
takerAssetAmounts,
|
||||||
|
@ -13,10 +13,7 @@ export * from '../test/generated-wrappers/eth2_dai_sampler';
|
|||||||
export * from '../test/generated-wrappers/i_balancer';
|
export * from '../test/generated-wrappers/i_balancer';
|
||||||
export * from '../test/generated-wrappers/i_curve';
|
export * from '../test/generated-wrappers/i_curve';
|
||||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||||
export * from '../test/generated-wrappers/i_kyber_hint_handler';
|
|
||||||
export * from '../test/generated-wrappers/i_kyber_network';
|
export * from '../test/generated-wrappers/i_kyber_network';
|
||||||
export * from '../test/generated-wrappers/i_kyber_network_proxy';
|
|
||||||
export * from '../test/generated-wrappers/i_kyber_storage';
|
|
||||||
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_m_stable';
|
export * from '../test/generated-wrappers/i_m_stable';
|
||||||
|
@ -18,10 +18,7 @@
|
|||||||
"test/generated-artifacts/IBalancer.json",
|
"test/generated-artifacts/IBalancer.json",
|
||||||
"test/generated-artifacts/ICurve.json",
|
"test/generated-artifacts/ICurve.json",
|
||||||
"test/generated-artifacts/IEth2Dai.json",
|
"test/generated-artifacts/IEth2Dai.json",
|
||||||
"test/generated-artifacts/IKyberHintHandler.json",
|
|
||||||
"test/generated-artifacts/IKyberNetwork.json",
|
"test/generated-artifacts/IKyberNetwork.json",
|
||||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
|
||||||
"test/generated-artifacts/IKyberStorage.json",
|
|
||||||
"test/generated-artifacts/ILiquidityProvider.json",
|
"test/generated-artifacts/ILiquidityProvider.json",
|
||||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
||||||
"test/generated-artifacts/IMStable.json",
|
"test/generated-artifacts/IMStable.json",
|
||||||
|
@ -37,6 +37,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Redeploy `MooniswapBridge` on Mainnet",
|
"note": "Redeploy `MooniswapBridge` on Mainnet",
|
||||||
"pr": 2681
|
"pr": 2681
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Redeploy `KyberBridge` on Mainnet",
|
||||||
|
"pr": 2683
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
"uniswapBridge": "0x36691c4f426eb8f42f150ebde43069a31cb080ad",
|
"uniswapBridge": "0x36691c4f426eb8f42f150ebde43069a31cb080ad",
|
||||||
"uniswapV2Bridge": "0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48",
|
"uniswapV2Bridge": "0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48",
|
||||||
"erc20BridgeSampler": "0xd8c38704c9937ea3312de29f824b4ad3450a5e61",
|
"erc20BridgeSampler": "0xd8c38704c9937ea3312de29f824b4ad3450a5e61",
|
||||||
"kyberBridge": "0x1c29670f7a77f1052d30813a0a4f632c78a02610",
|
"kyberBridge": "0xadd97271402590564ddd8ad23cb5317b1fb0fffb",
|
||||||
"eth2DaiBridge": "0x991c745401d5b5e469b8c3e2cb02c748f08754f1",
|
"eth2DaiBridge": "0x991c745401d5b5e469b8c3e2cb02c748f08754f1",
|
||||||
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
|
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
|
||||||
"dydxBridge": "0x92af95e37afddac412e5688a9dcc1dd815d4ae53",
|
"dydxBridge": "0x92af95e37afddac412e5688a9dcc1dd815d4ae53",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user