feat: kyber integration

This commit is contained in:
Richard Ramos 2020-03-20 08:04:05 -04:00
parent 52f6fb16e5
commit bdda80aeaf
3 changed files with 219 additions and 7 deletions

View File

@ -33,15 +33,12 @@ module.exports = {
'https://ropsten.infura.io/v3/8675214b97b44e96b70d05326c61fd6a',
],
deploy: {
MiniMeTokenFactory: {
deploy: false,
},
MiniMeToken: {
address: '0xc55cf4b03948d7ebc8b9e8bad92643703811d162',
},
Discover: {
address: '0xC8d48B421eAFdD75d5144E8f06882Cb5F0746Bd2',
args:["0xbF5d8683b9BE6C43fcA607eb2a6f2626A18837a6"]
},
DiscoverKyberSwap: {
args: ["$Discover", "0x818E6FECD516Ecc3849DAf6845e3EC868087B755", "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "0xbF5d8683b9BE6C43fcA607eb2a6f2626A18837a6", "0x0000000000000000000000000000000000000000", 20]
}
},
tracking: 'shared.testnet.chains.json',
},
@ -61,6 +58,9 @@ module.exports = {
Discover: {
address: '0x5bCF2767F86f14eDd82053bfBfd5069F68C2C5F8',
},
DiscoverKyberSwap: {
args: ["$Discover", "0x818E6FECD516Ecc3849DAf6845e3EC868087B755", "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "0x744d70fdbe2ba4cf95131626614a1763df805b9e", "0x0000000000000000000000000000000000000000", 20]
}
},
tracking: 'shared.mainnet.chains.json',
},

View File

@ -0,0 +1,145 @@
pragma solidity ^0.5.2;
import "./kyber/KyberNetworkProxy.sol";
import "./Discover.sol";
import "./token/ERC20Token.sol";
contract DiscoverKyberSwap is Controlled {
address public SNT;
address public ETH;
KyberNetworkProxy public kyberProxy;
Discover public discover;
address public walletId;
uint public maxSlippage;
/**
* @param _discover Discover contract address
* @param _kyberProxy Kyber Network Proxy address
* @param _ETH Kyber ETH address
* @param _SNT Kyber SNT address
* @param _walletId Wallet for Kyber network fees
* @param _maxSlippage Max slippage rate
*/
constructor(address _discover, address _kyberProxy, address _ETH, address _SNT, address _walletId, uint _maxSlippage) public {
require(_maxSlippage < 100);
discover = Discover(_discover);
kyberProxy = KyberNetworkProxy(_kyberProxy);
ETH = _ETH;
SNT = _SNT;
walletId = _walletId;
maxSlippage = _maxSlippage;
}
/**
* @notice Gets the conversion rate for the destToken given the srcQty.
* @param srcToken source token contract address
* @param srcQty amount of source tokens
* @return exchange rate
*/
function getConversionRates(address srcToken, uint srcQty) public view returns (uint expectedRate, uint slippageRate)
{
if(srcToken == address(0)){
srcToken = ETH;
}
(expectedRate, slippageRate) = kyberProxy.getExpectedRate(srcToken, SNT, srcQty);
require(expectedRate > 0);
}
/**
* @notice Upvote in discover
* @dev Requires a msg.value if using ETH
* @param _id Id to upvote
* @param _token Token to convert to SNT (see https://developer.kyber.network/docs/Environments-Intro/). Address 0 can be used for ETH too
* @param _amount Amount of tokens/eth to convert
*/
function upvote(bytes32 _id, address _token, uint _amount) public payable {
uint sntAmount = _tradeTokens(_token, _amount);
discover.upvote(_id, sntAmount);
}
/**
* @notice Downvote in discover
* @dev Requires a msg.value if using ETH
* @param _id Id to upvote
* @param _token Token to convert to SNT (see https://developer.kyber.network/docs/Environments-Intro/). Address 0 can be used for ETH too
* @param _amount Amount of tokens/eth to convert
*/
function downvote(bytes32 _id, address _token, uint _amount) public payable {
uint sntAmount = _tradeTokens(_token, _amount);
discover.downvote(_id, sntAmount);
}
/**
* @dev Trades tokens/ETH to SNT using Kyber
* @param _token Token to convert to SNT (see https://developer.kyber.network/docs/Environments-Intro/). Address 0 can be used for ETH too
* @param _amount Amount of tokens/eth to convert
* @return Amount of SNT received from the conversion
*/
function _tradeTokens(address _token, uint _amount) internal returns(uint sntAmount) {
uint minConversionRate;
uint slippageRate;
uint slippagePercent;
ERC20Token sntToken = ERC20Token(SNT);
if (_token == address(0) || _token == ETH) {
require(msg.value == _amount, "Not enough ETH");
(minConversionRate, slippageRate) = getConversionRates(ETH, _amount);
slippagePercent = 100 - ((slippageRate * 100) / minConversionRate);
require(slippagePercent <= maxSlippage);
sntAmount = kyberProxy.trade.value(_amount)(ETH, _amount, SNT, address(this), 0 - uint256(1), minConversionRate, walletId);
} else {
ERC20Token t = ERC20Token(_token);
// Initially transfer the tokens from the user to this contract
require(t.transferFrom(msg.sender, address(this), _amount));
if (_token != SNT) {
// Mitigate ERC20 Approve front-running attack, by initially setting allowance to 0
require(t.approve(address(kyberProxy), 0), "Could not reset token approval");
// Set the spender's token allowance to tokenQty
require(t.approve(address(kyberProxy), _amount), "Could not approve token amount");
(minConversionRate, slippageRate) = getConversionRates(_token, _amount);
slippagePercent = 100 - ((slippageRate * 100) / minConversionRate);
require(slippagePercent <= maxSlippage);
sntAmount = kyberProxy.trade(_token, _amount, SNT, address(this), 0 - uint256(1), minConversionRate, walletId);
} else {
sntAmount = _amount;
}
}
require(sntAmount != 0, "Not enough SNT for vote");
require(sntToken.approve(address(discover), 0), "Could not reset SNT approval");
require(sntToken.approve(address(discover), sntAmount), "Could not approve SNT amount");
}
event WalletIdChanged(address sender, address prevWalletId, address newWalletId);
/**
* @dev Changes the walletId address (for the fee sharing program)
* @param _walletId New walletId address
*/
function setWalletId(address _walletId) external onlyController {
emit WalletIdChanged(msg.sender, walletId, _walletId);
walletId = _walletId;
}
event SlippageUpdated(uint maxSlippage);
/**
* @param _maxSlippage most slippage as a percentage
*/
function setSlippage(uint _maxSlippage) public onlyController {
require(_maxSlippage < 100);
maxSlippage = _maxSlippage;
emit SlippageUpdated(_maxSlippage);
}
}

View File

@ -0,0 +1,67 @@
pragma solidity >=0.5.0 <0.6.0;
/**
* @title KyberNetworkProxy
* @dev Mock of the KyberNetworkProxy. Only used in development
*/
contract KyberNetworkProxy {
constructor() public {
}
/**
* @dev Get a mocked up rate for the trade
*/
function getExpectedRate(
address /* src */,
address /* dest */,
uint /* srcQty */
)
public pure
returns(uint expectedRate, uint slippageRate)
{
return (32749000000000000000, 31766530000000000000);
}
/// @notice use token address ETH_TOKEN_ADDRESS for ether
/// @dev makes a trade between src and dest token and send dest token to destAddress
/// @param maxDestAmount A limit on the amount of dest tokens
/// @return amount of actual dest tokens
function trade(
address /* src */,
uint /* srcAmount */,
address /* dest */,
address /* destAddress */,
uint maxDestAmount,
uint /* minConversionRate */,
address /* walletId */
)
public
payable
returns(uint)
{
return maxDestAmount;
}
/// @dev makes a trade between src and dest token and send dest tokens to msg sender
/// @return amount of actual dest tokens
function swapTokenToToken(
address /* src */,
uint /* srcAmount */,
address /* dest */,
uint /* minConversionRate */
)
public pure
returns(uint)
{
return 100;
}
/// @dev makes a trade from Ether to token. Sends token to msg sender
/// @return amount of actual dest tokens
function swapEtherToToken(
address /* token */,
uint /* minConversionRate */
) public payable returns(uint) {
return 200;
}
}