1+ /*
2+ Copyright 2021 Set Labs Inc.
3+
4+ Licensed under the Apache License, Version 2.0 (the "License");
5+ you may not use this file except in compliance with the License.
6+ You may obtain a copy of the License at
7+
8+ http://www.apache.org/licenses/LICENSE-2.0
9+
10+ Unless required by applicable law or agreed to in writing, software
11+ distributed under the License is distributed on an "AS IS" BASIS,
12+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ See the License for the specific language governing permissions and
14+ limitations under the License.
15+
16+ SPDX-License-Identifier: Apache License, Version 2.0
17+ */
18+
19+ pragma solidity 0.6.10 ;
20+ pragma experimental "ABIEncoderV2 " ;
21+
22+ import { BytesLib } from "external/contracts/uniswap/v3/lib/BytesLib.sol " ;
23+ import { IDMMFactory } from "../../../interfaces/external/IDMMFactory.sol " ;
24+ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
25+ import { IIndexExchangeAdapter } from "../../../interfaces/IIndexExchangeAdapter.sol " ;
26+
27+ /**
28+ * @title KyberV3IndexExchangeAdapter
29+ * @author Set Protocol
30+ *
31+ * A Kyber V3 DMM exchange adapter that returns calldata for trading with GeneralIndexModule, allows encoding a trade with a fixed input quantity or
32+ * a fixed output quantity.
33+ */
34+ contract KyberV3IndexExchangeAdapter is IIndexExchangeAdapter {
35+
36+ using BytesLib for bytes ;
37+
38+ /* ============ Constants ============ */
39+
40+ // DMMRouter function string for swapping exact tokens for a minimum of receive tokens
41+ string internal constant SWAP_EXACT_TOKENS_FOR_TOKENS = "swapExactTokensForTokens(uint256,uint256,address[],address[],address,uint256) " ;
42+ // DMMRouter function string for swapping tokens for an exact amount of receive tokens
43+ string internal constant SWAP_TOKENS_FOR_EXACT_TOKENS = "swapTokensForExactTokens(uint256,uint256,address[],address[],address,uint256) " ;
44+
45+ /* ============ State Variables ============ */
46+
47+ address public immutable dmmRouter;
48+ IDMMFactory public immutable dmmFactory;
49+
50+ /* ============ Constructor ============ */
51+
52+ /**
53+ * Set state variables
54+ *
55+ * @param _dmmRouter Address of Kyber V3 DMM Router
56+ * @param _dmmFactory Address of Kyber V3 DMM Factory
57+ */
58+ constructor (address _dmmRouter , IDMMFactory _dmmFactory ) public {
59+ dmmRouter = _dmmRouter;
60+ dmmFactory = _dmmFactory;
61+ }
62+
63+ /* ============ External Getter Functions ============ */
64+
65+ /**
66+ * Return calldata for trading with Kyber V3 DMM Router. Trade paths are created from _sourceToken and
67+ * _destinationToken. On Kyber DMM exchange, for each token pair, there can be possibly many multiple pools with
68+ * different configurations for the pricing curve. Hence the address of the pool to be used for trading must be passed
69+ * in the _data parameter.
70+ *
71+ * ---------------------------------------------------------------------------------------------------------------
72+ * _isSendTokenFixed | Parameter | Amount |
73+ * ---------------------------------------------------------------------------------------------------------------
74+ * True | _sourceQuantity | Fixed amount of _sourceToken to trade |
75+ * | _destinationQuantity | Minimum amount of _destinationToken willing to receive |
76+ * ---------------------------------------------------------------------------------------------------------------
77+ * False | _sourceQuantity | Maximum amount of _sourceToken to trade |
78+ * | _destinationQuantity | Fixed amount of _destinationToken want to receive |
79+ * ---------------------------------------------------------------------------------------------------------------
80+ *
81+ * @param _sourceToken Address of source token to be sold
82+ * @param _destinationToken Address of destination token to buy
83+ * @param _destinationAddress Address that assets should be transferred to
84+ * @param _isSendTokenFixed Boolean indicating if the send quantity is fixed, used to determine correct trade interface
85+ * @param _sourceQuantity Fixed/Max amount of source token to sell
86+ * @param _destinationQuantity Min/Fixed amount of destination token to buy
87+ * @param _data Arbitray bytes containing the pool address to be used for trading. Can use
88+ * `getPoolWithBestLiquidity()` to get the most liquid pool for a given pair of tokens
89+ * on the Kyber DMM exchange.
90+ *
91+ * @return address Target contract address
92+ * @return uint256 Call value
93+ * @return bytes Trade calldata
94+ */
95+ function getTradeCalldata (
96+ address _sourceToken ,
97+ address _destinationToken ,
98+ address _destinationAddress ,
99+ bool _isSendTokenFixed ,
100+ uint256 _sourceQuantity ,
101+ uint256 _destinationQuantity ,
102+ bytes memory _data
103+ )
104+ external
105+ view
106+ override
107+ returns (address , uint256 , bytes memory )
108+ {
109+
110+ address [] memory path = new address [](2 );
111+ path[0 ] = _sourceToken;
112+ path[1 ] = _destinationToken;
113+
114+ address [] memory poolsPath = new address [](1 );
115+ poolsPath[0 ] = _data.toAddress (0 );
116+
117+ require (dmmFactory.isPool (IERC20 (_sourceToken), IERC20 (_destinationToken), poolsPath[0 ]), "Invalid pool address " );
118+
119+ bytes memory callData = abi.encodeWithSignature (
120+ _isSendTokenFixed ? SWAP_EXACT_TOKENS_FOR_TOKENS : SWAP_TOKENS_FOR_EXACT_TOKENS,
121+ _isSendTokenFixed ? _sourceQuantity : _destinationQuantity,
122+ _isSendTokenFixed ? _destinationQuantity : _sourceQuantity,
123+ poolsPath,
124+ path,
125+ _destinationAddress,
126+ block .timestamp
127+ );
128+ return (dmmRouter, 0 , callData);
129+ }
130+
131+ /**
132+ * Returns the address to approve source tokens to for trading. This is the Kyber DMM Router.
133+ *
134+ * @return address Address of the contract to approve tokens to
135+ */
136+ function getSpender () external view override returns (address ) {
137+ return dmmRouter;
138+ }
139+ }
0 commit comments