Created
September 25, 2018 07:10
-
-
Save asoong/d50d0b35727d8377f3f9a47ea07256e2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright 2018 Set Labs Inc. | |
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.4.24; | |
pragma experimental "ABIEncoderV2"; | |
import { SafeMath } from "zeppelin-solidity/contracts/math/SafeMath.sol"; | |
import { Authorizable } from "../../lib/Authorizable.sol"; | |
import { ERC20Wrapper as ERC20 } from "../../lib/ERC20Wrapper.sol"; | |
import { KyberNetworkProxyInterface } from "../../external/KyberNetwork/KyberNetworkProxyInterface.sol"; | |
import { LibBytes } from "../../external/0x/LibBytes.sol"; | |
/** | |
* @title KyberNetworkWrapper | |
* @author Set Protocol | |
* | |
* The KyberNetworkWrapper contract wrapper to interface with KyberNetwork for reserve liquidity | |
*/ | |
contract KyberNetworkWrapper is | |
Authorizable | |
{ | |
using SafeMath for uint256; | |
using LibBytes for bytes; | |
/* ============ State Variables ============ */ | |
address public kyberNetworkProxy; | |
address public setTransferProxy; | |
// ============ Structs ============ | |
struct KyberTrade { | |
address sourceToken; | |
address destinationToken; | |
uint256 sourceTokenQuantity; | |
uint256 minimumConversionRate; | |
uint256 maxDestinationQuantity; | |
} | |
/* ============ Constructor ============ */ | |
/** | |
* Initialize exchange wrapper with required addresses to facilitate Kyber trades | |
* | |
* @param _kyberNetworkProxy KyberNetwork contract for filling orders | |
* @param _setTransferProxy Set Protocol transfer proxy contract | |
*/ | |
constructor( | |
address _kyberNetworkProxy, | |
address _setTransferProxy | |
) | |
public | |
Authorizable(2592000) // about 4 weeks | |
{ | |
kyberNetworkProxy = _kyberNetworkProxy; | |
setTransferProxy = _setTransferProxy; | |
} | |
/* ============ Public Functions ============ */ | |
/** | |
* IExchangeWrapper interface delegate method. | |
* Parses and executes Kyber trades | |
* | |
* TODO: Currently passes change back to the issuance order maker | |
* | |
* @param _maker Unused address of issuance order signer to conform to IExchangeWrapper | |
* @param _ Unused address of fillOrder caller to conform to IExchangeWrapper | |
* @param _tradeCount Amount of trades in exchange request | |
* @param _tradesData Byte string containing (multiple) 0x wrapper orders | |
* @return address[] Array of token addresses executed in orders | |
* @return uint256[] Array of token amounts executed in orders | |
*/ | |
function exchange( | |
address _maker, | |
address _, | |
uint256 _tradeCount, | |
bytes _tradesData | |
) | |
external | |
onlyAuthorized | |
returns (address[], uint256[]) | |
{ | |
address[] memory takerTokens = new address[](_tradeCount); | |
uint256[] memory takerAmounts = new uint256[](_tradeCount); | |
uint256 scannedBytes = 0; | |
for (uint256 i = 0; i < _tradeCount; i++) { | |
// Parse Kyber trade of current offset | |
KyberTrade memory trade = parseKyberTrade( | |
_tradesData, | |
scannedBytes | |
); | |
// Execute the trade via the KyberNetworkProxy | |
takerTokens[i] = trade.destinationToken; | |
takerAmounts[i] = tradeOnKyberReserve( | |
trade, | |
_maker | |
); | |
// Update current bytes | |
scannedBytes = scannedBytes.add(160); | |
} | |
return ( | |
takerTokens, | |
takerAmounts | |
); | |
} | |
/* ============ Private ============ */ | |
/** | |
* Executes Kyber trade | |
* | |
* @param _trade Kyber trade parameter struct | |
* @param _maker Address of issuance order maker to pass change to | |
* @return address Address of set component to trade for | |
* @return uint256 Amount of set component received in trade | |
*/ | |
function tradeOnKyberReserve( | |
KyberTrade memory _trade, | |
address _maker | |
) | |
private | |
returns (uint256) | |
{ | |
// Ensure the source token is allowed to be transferred by KyberNetworkProxy Proxy | |
ERC20.ensureAllowance( | |
_trade.sourceToken, | |
address(this), | |
kyberNetworkProxy, | |
_trade.sourceTokenQuantity | |
); | |
// TODO: This returned rate is ALWAYS 0 | |
// uint256 rate; | |
// uint256 slippage; | |
// (rate, slippage) = KyberNetworkProxyInterface(kyberNetworkProxy).getExpectedRate( | |
// _trade.sourceToken, | |
// _trade.destinationToken, | |
// _trade.sourceTokenQuantity | |
// ); | |
uint256 destinationTokenQuantity = KyberNetworkProxyInterface(kyberNetworkProxy).trade( | |
_trade.sourceToken, | |
_trade.sourceTokenQuantity, | |
_trade.destinationToken, | |
address(this), | |
_trade.maxDestinationQuantity, | |
_trade.minimumConversionRate, | |
0 | |
); | |
// Transfer any unused issuance order maker token back to user | |
uint remainderSourceToken = _trade.sourceTokenQuantity.sub(ERC20.balanceOf(_trade.sourceToken, this)); | |
ERC20.transfer( | |
_trade.sourceToken, | |
_maker, | |
remainderSourceToken | |
); | |
// Ensure the maker token is allowed to be transferred by Set TransferProxy | |
ERC20.ensureAllowance( | |
_trade.destinationToken, | |
address(this), | |
setTransferProxy, | |
destinationTokenQuantity | |
); | |
return destinationTokenQuantity; | |
} | |
/* | |
* Parses the bytes array for a Kyber trade | |
* | |
* | Data | Location | | |
* |----------------------------|-------------------------------| | |
* | sourceToken | 0 | | |
* | destinationToken | 32 | | |
* | sourceTokenQuantity | 64 | | |
* | minimumConversionRate | 98 | | |
* | maxDestinationQuantity | 128 | | |
* | |
* @param _tradesData Byte array of (multiple) Kyber trades | |
* @param _offset Offset to start scanning for Kyber trade body | |
* @return KyberTrade KyberTrade struct | |
*/ | |
function parseKyberTrade( | |
bytes _tradesData, | |
uint256 _offset | |
) | |
private | |
pure | |
returns (KyberTrade memory) | |
{ | |
KyberTrade memory trade; | |
uint256 tradeDataStart = _tradesData.contentAddress().add(_offset); | |
assembly { | |
mstore(trade, mload(tradeDataStart)) // sourceToken | |
mstore(add(trade, 32), mload(add(tradeDataStart, 32))) // destinationToken | |
mstore(add(trade, 64), mload(add(tradeDataStart, 64))) // sourceTokenQuantity | |
mstore(add(trade, 96), mload(add(tradeDataStart, 96))) // minimumConversionRate | |
mstore(add(trade, 128), mload(add(tradeDataStart, 128))) // maxDestinationQuantity | |
} | |
return trade; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment