feat: better Kyber quotes (#2683)

* feat: Kyber rework

* Get additional reserves per token
This commit is contained in:
Jacob Evans
2020-08-27 15:58:57 +10:00
committed by GitHub
parent 2f9b894d71
commit a2f0d5eedf
28 changed files with 444 additions and 394 deletions

View File

@@ -21,6 +21,10 @@
{
"note": "Added `MooniswapBridge`",
"pr": 2675
},
{
"note": "Reworked `KyberBridge`",
"pr": 2683
}
]
},

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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()