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`",
|
||||
"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");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -45,6 +45,7 @@ contract KyberBridge is
|
||||
uint256 fromTokenBalance;
|
||||
uint256 payableAmount;
|
||||
uint256 conversionRate;
|
||||
bytes hint;
|
||||
}
|
||||
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
@ -85,47 +86,35 @@ contract KyberBridge is
|
||||
state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
// 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.
|
||||
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
||||
if (state.fromTokenBalance == 0) {
|
||||
// Return failure if no input tokens.
|
||||
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) {
|
||||
// Just transfer the tokens if they're the same.
|
||||
LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
|
||||
return BRIDGE_SUCCESS;
|
||||
} else if (state.fromTokenAddress != address(state.weth)) {
|
||||
// If the input token is not WETH, grant an allowance to the exchange
|
||||
// to spend them.
|
||||
}
|
||||
if (state.fromTokenAddress == address(state.weth)) {
|
||||
// From WETH
|
||||
state.fromTokenAddress = KYBER_ETH_ADDRESS;
|
||||
state.payableAmount = state.fromTokenBalance;
|
||||
state.weth.withdraw(state.fromTokenBalance);
|
||||
} else {
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.fromTokenAddress,
|
||||
address(state.kyber),
|
||||
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);
|
||||
|
||||
// Try to sell all of this contract's input token balance through
|
||||
// `KyberNetworkProxy.trade()`.
|
||||
uint256 boughtAmount = state.kyber.trade.value(state.payableAmount)(
|
||||
uint256 boughtAmount = state.kyber.tradeWithHint.value(state.payableAmount)(
|
||||
// Input token.
|
||||
state.fromTokenAddress,
|
||||
// Sell amount.
|
||||
@ -137,11 +126,11 @@ contract KyberBridge is
|
||||
isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
|
||||
// Buy as much as possible.
|
||||
uint256(-1),
|
||||
// Compute the minimum conversion rate, which is expressed in units with
|
||||
// 18 decimal places.
|
||||
state.conversionRate,
|
||||
// The minimum conversion rate
|
||||
1,
|
||||
// No affiliate address.
|
||||
address(0)
|
||||
address(0),
|
||||
state.hint
|
||||
);
|
||||
// Wrap ETH output and transfer to recipient.
|
||||
if (isToTokenWeth) {
|
||||
@ -173,4 +162,5 @@ contract KyberBridge is
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,5 +42,31 @@ interface IKyberNetworkProxy {
|
||||
)
|
||||
external
|
||||
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");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -28,6 +28,8 @@ contract DeploymentConstants {
|
||||
address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
/// @dev Mainnet address of the KyberNetworkProxy contract.
|
||||
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.
|
||||
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||
/// @dev Mainnet address of the `UniswapV2Router01` contract.
|
||||
@ -155,6 +157,16 @@ contract DeploymentConstants {
|
||||
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.
|
||||
/// @return wethAddress The WETH address.
|
||||
function _getWethAddress()
|
||||
|
@ -73,6 +73,10 @@
|
||||
{
|
||||
"note": "Use on-chain sampling (sometimes) for Balancer",
|
||||
"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");
|
||||
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 "./interfaces/IKyberNetwork.sol";
|
||||
import "./interfaces/IKyberNetworkProxy.sol";
|
||||
import "./interfaces/IKyberStorage.sol";
|
||||
import "./interfaces/IKyberHintHandler.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
@ -34,73 +31,130 @@ contract KyberSampler is
|
||||
ApproximateBuys
|
||||
{
|
||||
/// @dev Gas limit for Kyber calls.
|
||||
uint256 constant private KYBER_CALL_GAS = 1500e3; // 1.5m
|
||||
/// @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;
|
||||
uint256 constant private KYBER_CALL_GAS = 500e3; // 500k
|
||||
|
||||
/// @dev Sample sell quotes from Kyber.
|
||||
/// @param reserveId The selected kyber reserve
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
/// @return hint The hint for the selected reserve
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token amount.
|
||||
function sampleSellsFromKyberNetwork(
|
||||
bytes32 reserveId,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (bytes memory hint, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
address wethAddress = _getWethAddress();
|
||||
uint256 value;
|
||||
hint = this.encodeKyberHint(reserveId, takerToken, makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
if (takerToken == wethAddress || makerToken == wethAddress) {
|
||||
// Direct ETH based trade
|
||||
value = _sampleSellFromKyberNetwork(takerToken, makerToken, takerTokenAmounts[i]);
|
||||
} else {
|
||||
// Hop to ETH
|
||||
value = _sampleSellFromKyberNetwork(takerToken, wethAddress, takerTokenAmounts[i]);
|
||||
if (value != 0) {
|
||||
value = _sampleSellFromKyberNetwork(wethAddress, makerToken, value);
|
||||
}
|
||||
uint256 value = this.sampleSellFromKyberNetwork(hint, takerToken, makerToken, takerTokenAmounts[i]);
|
||||
// Return early if the source has no liquidity
|
||||
if (value == 0) {
|
||||
return (hint, makerTokenAmounts);
|
||||
}
|
||||
makerTokenAmounts[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Kyber.
|
||||
/// @param reserveId The selected kyber reserve
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
/// @return hint The hint for the selected reserve
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token amount.
|
||||
function sampleBuysFromKyberNetwork(
|
||||
bytes32 reserveId,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (bytes memory hint, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
return _sampleApproximateBuys(
|
||||
hint = this.encodeKyberHint(reserveId, takerToken, makerToken);
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken),
|
||||
takerTokenData: abi.encode(takerToken),
|
||||
makerTokenData: abi.encode(makerToken, hint),
|
||||
takerTokenData: abi.encode(takerToken, hint),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromKyber
|
||||
}),
|
||||
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(
|
||||
@ -112,82 +166,40 @@ contract KyberSampler is
|
||||
view
|
||||
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) =
|
||||
address(this).staticcall(abi.encodeWithSelector(
|
||||
this.sampleSellsFromKyberNetwork.selector,
|
||||
abi.decode(takerTokenData, (address)),
|
||||
abi.decode(makerTokenData, (address)),
|
||||
_toSingleValueArray(sellAmount)
|
||||
this.sampleSellFromKyberNetwork.selector,
|
||||
hint,
|
||||
takerToken,
|
||||
makerToken,
|
||||
sellAmount
|
||||
));
|
||||
if (!success) {
|
||||
return 0;
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
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(
|
||||
function sampleSellFromKyberNetwork(
|
||||
bytes memory hint,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
private
|
||||
public
|
||||
view
|
||||
returns (uint256 makerTokenAmount)
|
||||
{
|
||||
(IKyberHintHandler kyberHint, IKyberStorage kyberStorage) = _getKyberAddresses();
|
||||
// Ban reserves which can clash with our internal aggregation
|
||||
bytes32[] memory reserveIds = kyberStorage.getReserveIdsPerTokenSrc(
|
||||
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));
|
||||
// If there is no hint do not continue
|
||||
if (hint.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getKyberNetworkProxyAddress().staticcall.gas(KYBER_CALL_GAS)(
|
||||
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;
|
||||
|
||||
import "./IKyberStorage.sol";
|
||||
import "./IKyberHintHandler.sol";
|
||||
|
||||
|
||||
// Keepin everything together
|
||||
interface IKyberNetwork {
|
||||
|
||||
function getContracts()
|
||||
|
||||
}
|
||||
|
||||
|
||||
interface IKyberNetworkProxy {
|
||||
|
||||
function getExpectedRateAfterFee(
|
||||
address src,
|
||||
address dest,
|
||||
uint256 srcQty,
|
||||
uint256 platformFeeBps,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
address kyberFeeHandlerAddress,
|
||||
address kyberDaoAddress,
|
||||
IKyberHintHandler kyberMatchingEngineAddress,
|
||||
IKyberStorage kyberStorageAddress,
|
||||
address gasHelperAddress,
|
||||
address[] memory kyberProxyAddresses);
|
||||
returns (uint256 expectedRate);
|
||||
}
|
||||
|
||||
interface IKyberHintHandler {
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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 "../src/ERC20BridgeSampler.sol";
|
||||
import "../src/interfaces/IEth2Dai.sol";
|
||||
import "../src/interfaces/IKyberNetworkProxy.sol";
|
||||
import "../src/interfaces/IKyberNetwork.sol";
|
||||
import "../src/interfaces/IUniswapV2Router01.sol";
|
||||
|
||||
|
||||
@ -253,76 +253,40 @@ contract TestERC20BridgeSamplerKyberNetwork is
|
||||
|
||||
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
|
||||
function buildTokenToEthHint(
|
||||
address /* tokenSrc */,
|
||||
address tokenSrc,
|
||||
TradeType /* tokenToEthType */,
|
||||
bytes32[] calldata /* tokenToEthReserveIds */,
|
||||
uint256[] calldata /* tokenToEthSplits */
|
||||
) external view returns (bytes memory hint)
|
||||
{
|
||||
return hint;
|
||||
return abi.encode(tokenSrc);
|
||||
}
|
||||
|
||||
function buildEthToTokenHint(
|
||||
address /* tokenDest */,
|
||||
address tokenDest,
|
||||
TradeType /* ethToTokenType */,
|
||||
bytes32[] calldata /* ethToTokenReserveIds */,
|
||||
uint256[] calldata /* ethToTokenSplits */
|
||||
) 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()`.
|
||||
@ -375,6 +339,14 @@ contract TestERC20BridgeSamplerKyberNetwork is
|
||||
{
|
||||
return address(this);
|
||||
}
|
||||
|
||||
function _getKyberHintHandlerAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -533,4 +505,13 @@ contract TestERC20BridgeSampler is
|
||||
{
|
||||
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": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
||||
"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": {
|
||||
"assets": []
|
||||
}
|
||||
|
@ -122,8 +122,8 @@ export {
|
||||
SamplerContractOperation,
|
||||
} from './utils/market_operation_utils/sampler_contract_operation';
|
||||
export {
|
||||
BancorFillData,
|
||||
BalancerFillData,
|
||||
BancorFillData,
|
||||
CollapsedFill,
|
||||
CurveFillData,
|
||||
CurveFunctionSelectors,
|
||||
@ -135,6 +135,7 @@ export {
|
||||
FillData,
|
||||
FillFlags,
|
||||
GetMarketOrdersRfqtOpts,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
MarketDepth,
|
||||
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 WALLET_SIGNATURE = '0x04';
|
||||
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,
|
||||
ERC20BridgeSource,
|
||||
Fill,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
MultiBridgeFillData,
|
||||
MultiHopFillData,
|
||||
@ -295,6 +296,14 @@ function createBridgeOrder(
|
||||
createMultiBridgeData(takerToken, makerToken),
|
||||
);
|
||||
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:
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
makerToken,
|
||||
@ -393,6 +402,11 @@ function createBancorBridgeData(path: string[], networkAddress: string): string
|
||||
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(
|
||||
curveAddress: string,
|
||||
exchangeFunctionSelector: string,
|
||||
|
@ -8,6 +8,7 @@ import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote }
|
||||
import { BancorService } from './bancor_service';
|
||||
import { MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants';
|
||||
import { getCurveInfosForPair } from './curve_utils';
|
||||
import { getKyberReserveIdsForPair } from './kyber_utils';
|
||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
||||
import { getIntermediateTokens } from './multihop_utils';
|
||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||
@ -20,6 +21,7 @@ import {
|
||||
DexSample,
|
||||
ERC20BridgeSource,
|
||||
HopInfo,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
MultiBridgeFillData,
|
||||
MultiHopFillData,
|
||||
@ -71,6 +73,7 @@ export class SamplerOperations {
|
||||
}
|
||||
|
||||
public getKyberSellQuotes(
|
||||
reserveId: string,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
@ -79,11 +82,21 @@ export class SamplerOperations {
|
||||
source: ERC20BridgeSource.Kyber,
|
||||
contract: this._samplerContract,
|
||||
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(
|
||||
reserveId: string,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
@ -92,7 +105,16 @@ export class SamplerOperations {
|
||||
source: ERC20BridgeSource.Kyber,
|
||||
contract: this._samplerContract,
|
||||
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;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return this.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>
|
||||
this.getKyberSellQuotes(reserveId, makerToken, takerToken, takerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.Curve:
|
||||
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
||||
this.getCurveSellQuotes(
|
||||
@ -825,7 +849,9 @@ export class SamplerOperations {
|
||||
}
|
||||
return ops;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return this.getKyberBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>
|
||||
this.getKyberBuyQuotes(reserveId, makerToken, takerToken, makerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.Curve:
|
||||
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
||||
this.getCurveBuyQuotes(
|
||||
|
@ -108,6 +108,11 @@ export interface BancorFillData extends FillData {
|
||||
networkAddress: string;
|
||||
}
|
||||
|
||||
export interface KyberFillData extends FillData {
|
||||
hint: string;
|
||||
reserveId: string;
|
||||
}
|
||||
|
||||
export interface Quote<TFillData = FillData> {
|
||||
amount: BigNumber;
|
||||
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 ICurve from '../test/generated-artifacts/ICurve.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 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 ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
|
||||
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
|
||||
@ -58,10 +55,7 @@ export const artifacts = {
|
||||
IBalancer: IBalancer as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IKyberHintHandler: IKyberHintHandler as ContractArtifact,
|
||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
|
||||
IKyberStorage: IKyberStorage as ContractArtifact,
|
||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
|
@ -81,24 +81,25 @@ blockchainTests.skip('Mainnet Sampler Tests', env => {
|
||||
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||
const DAI = '0x6b175474e89094c44da98b954eedeac495271d0f';
|
||||
const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
|
||||
const RESERVE_ID = '0xff4b796265722046707200000000000000000000000000000000000000000000';
|
||||
describe('sampleSellsFromKyberNetwork()', () => {
|
||||
it('samples sells from Kyber DAI->WETH', async () => {
|
||||
const samples = await testContract
|
||||
.sampleSellsFromKyberNetwork(DAI, WETH, [toBaseUnitAmount(1)])
|
||||
const [, samples] = await testContract
|
||||
.sampleSellsFromKyberNetwork(RESERVE_ID, DAI, WETH, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
it('samples sells from Kyber WETH->DAI', async () => {
|
||||
const samples = await testContract
|
||||
.sampleSellsFromKyberNetwork(WETH, DAI, [toBaseUnitAmount(1)])
|
||||
const [, samples] = await testContract
|
||||
.sampleSellsFromKyberNetwork(RESERVE_ID, WETH, DAI, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
it('samples sells from Kyber DAI->USDC', async () => {
|
||||
const samples = await testContract
|
||||
.sampleSellsFromKyberNetwork(DAI, USDC, [toBaseUnitAmount(1)])
|
||||
const [, samples] = await testContract
|
||||
.sampleSellsFromKyberNetwork(RESERVE_ID, DAI, USDC, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).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 () => {
|
||||
// From ETH to DAI
|
||||
// I want to buy 1 DAI
|
||||
const samples = await testContract
|
||||
.sampleBuysFromKyberNetwork(WETH, DAI, [toBaseUnitAmount(1)])
|
||||
const [, samples] = await testContract
|
||||
.sampleBuysFromKyberNetwork(RESERVE_ID, WETH, DAI, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).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 () => {
|
||||
// From USDC to DAI
|
||||
// I want to buy 1 WETH
|
||||
const samples = await testContract
|
||||
.sampleBuysFromKyberNetwork(DAI, WETH, [toBaseUnitAmount(1)])
|
||||
const [, samples] = await testContract
|
||||
.sampleBuysFromKyberNetwork(RESERVE_ID, DAI, WETH, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).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 TAKER_TOKEN = randomAddress();
|
||||
const INTERMEDIATE_TOKEN = randomAddress();
|
||||
const KYBER_RESERVE_ID = '0x';
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
|
||||
@ -330,31 +331,25 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
it('can return no quotes', async () => {
|
||||
const quotes = await testContract.sampleSellsFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, []).callAsync();
|
||||
expect(quotes).to.deep.eq([]);
|
||||
});
|
||||
|
||||
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)
|
||||
const [, quotes] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
expect(quotes).to.deep.eq([]);
|
||||
});
|
||||
|
||||
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
|
||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@ -362,8 +357,17 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('can quote token -> ETH', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.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();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@ -372,8 +376,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@ -381,8 +385,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('can quote ETH -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@ -391,8 +395,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@ -405,21 +409,24 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
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([]);
|
||||
});
|
||||
|
||||
it('can quote token -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [ethToMakerQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, MAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], ethToMakerQuotes);
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
||||
});
|
||||
@ -428,8 +435,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@ -437,8 +444,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('can quote token -> ETH', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
||||
});
|
||||
@ -447,8 +454,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@ -456,8 +463,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('can quote ETH -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expectQuotesWithinRange(quotes, expectedQuotes, ACCEPTABLE_SLIPPAGE);
|
||||
});
|
||||
@ -466,8 +473,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
const [, quotes] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_RESERVE_ID, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
@ -135,16 +135,21 @@ describe('DexSampler tests', () => {
|
||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleSellsFromKyberNetwork: (takerToken, makerToken, fillAmounts) => {
|
||||
sampleSellsFromKyberNetwork: (_reserveId, takerToken, makerToken, fillAmounts) => {
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||
return expectedMakerFillAmounts;
|
||||
return ['0x', expectedMakerFillAmounts];
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getKyberSellQuotes(expectedMakerToken, expectedTakerToken, expectedTakerFillAmounts),
|
||||
dexOrderSampler.getKyberSellQuotes(
|
||||
'0x',
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
expectedTakerFillAmounts,
|
||||
),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||
});
|
||||
@ -373,12 +378,7 @@ describe('DexSampler tests', () => {
|
||||
it('getSellQuotes()', async () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
const sources = [
|
||||
ERC20BridgeSource.Kyber,
|
||||
ERC20BridgeSource.Eth2Dai,
|
||||
ERC20BridgeSource.Uniswap,
|
||||
ERC20BridgeSource.UniswapV2,
|
||||
];
|
||||
const sources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
|
||||
const ratesBySource: RatesBySource = {
|
||||
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
|
||||
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
||||
@ -387,12 +387,6 @@ describe('DexSampler tests', () => {
|
||||
};
|
||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||
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) => {
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
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)
|
||||
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));
|
||||
});
|
||||
it('getSellQuotes() uses samples from Balancer', async () => {
|
||||
|
@ -261,6 +261,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.UniswapV2]: { tokenAddressPath: [] },
|
||||
[ERC20BridgeSource.Balancer]: { poolAddress: randomAddress() },
|
||||
[ERC20BridgeSource.Bancor]: { path: [], networkAddress: randomAddress() },
|
||||
[ERC20BridgeSource.Kyber]: { hint: '0x', reserveId: '0x' },
|
||||
[ERC20BridgeSource.Curve]: {
|
||||
curve: {
|
||||
poolAddress: randomAddress(),
|
||||
|
@ -23,6 +23,18 @@ export type SampleBuysHandler = (
|
||||
makerToken: string,
|
||||
makerTokenAmounts: BigNumber[],
|
||||
) => 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 SampleSellsLPHandler = (
|
||||
registryAddress: string,
|
||||
@ -48,7 +60,7 @@ const DUMMY_PROVIDER = {
|
||||
interface Handlers {
|
||||
getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||
getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||
sampleSellsFromKyberNetwork: SampleSellsHandler;
|
||||
sampleSellsFromKyberNetwork: SampleSellsKyberHandler;
|
||||
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
||||
sampleSellsFromMultiBridge: SampleSellsMBHandler;
|
||||
sampleSellsFromEth2Dai: SampleSellsHandler;
|
||||
@ -104,13 +116,15 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract {
|
||||
}
|
||||
|
||||
public sampleSellsFromKyberNetwork(
|
||||
reserveId: string,
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
takerAssetAmounts: BigNumber[],
|
||||
): ContractFunctionObj<BigNumber[]> {
|
||||
): ContractFunctionObj<[string, BigNumber[]]> {
|
||||
return this._wrapCall(
|
||||
super.sampleSellsFromKyberNetwork,
|
||||
this._handlers.sampleSellsFromKyberNetwork,
|
||||
reserveId,
|
||||
takerToken,
|
||||
makerToken,
|
||||
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_curve';
|
||||
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_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_registry';
|
||||
export * from '../test/generated-wrappers/i_m_stable';
|
||||
|
@ -18,10 +18,7 @@
|
||||
"test/generated-artifacts/IBalancer.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberHintHandler.json",
|
||||
"test/generated-artifacts/IKyberNetwork.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
"test/generated-artifacts/IKyberStorage.json",
|
||||
"test/generated-artifacts/ILiquidityProvider.json",
|
||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/IMStable.json",
|
||||
|
@ -37,6 +37,10 @@
|
||||
{
|
||||
"note": "Redeploy `MooniswapBridge` on Mainnet",
|
||||
"pr": 2681
|
||||
},
|
||||
{
|
||||
"note": "Redeploy `KyberBridge` on Mainnet",
|
||||
"pr": 2683
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -22,7 +22,7 @@
|
||||
"uniswapBridge": "0x36691c4f426eb8f42f150ebde43069a31cb080ad",
|
||||
"uniswapV2Bridge": "0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48",
|
||||
"erc20BridgeSampler": "0xd8c38704c9937ea3312de29f824b4ad3450a5e61",
|
||||
"kyberBridge": "0x1c29670f7a77f1052d30813a0a4f632c78a02610",
|
||||
"kyberBridge": "0xadd97271402590564ddd8ad23cb5317b1fb0fffb",
|
||||
"eth2DaiBridge": "0x991c745401d5b5e469b8c3e2cb02c748f08754f1",
|
||||
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
|
||||
"dydxBridge": "0x92af95e37afddac412e5688a9dcc1dd815d4ae53",
|
||||
|
Loading…
x
Reference in New Issue
Block a user