Skip to content

Commit f728dc0

Browse files
authored
Add uniswap v3 index exchange adapter (#89)
* Add external Uniswap V3 contracts * Add UniswapV3 Index Exchange Adapter contract * Modify compiler-version in .solhint.json * Add tests * Fix coverage * Improve javadocs and add getEncodedTradePath() test * Use soldityPack in getEncodedTradePath test * Change compiler version to 0.6.10 * Add suggested changes * Remove getTradeEncodedPath function * Remove @uniswap/v3-periphery as dependency * Add @uniswap/v3-core as dependency * Use exactInputSingle and exactOutputSingle functions instead of exactInput and exactOutput * Move BytesLib to external/contracts/uniswap/v3 * Add Note to set exchange data in GIM * Remove @uniswap/v3-core dependency *Add suggested changes * Add getEncodedFeeData function and add suggested changes * Refactor tests to use UniswapV3 Fixture * Fix uniswap/v3/SwapRotuer ABI * Add integration tests with GIM * Trade DAI for WETH on UniswapV3 during rebalance * Trade WETH for WBTC on UniswapV3 during rebalance * Fix comment
1 parent 26c06b9 commit f728dc0

File tree

9 files changed

+565
-33
lines changed

9 files changed

+565
-33
lines changed

contracts/interfaces/external/ISwapRouter.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,4 @@ interface ISwapRouter {
6363
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
6464
/// @return amountIn The amount of the input token
6565
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
66-
}
66+
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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 { ISwapRouter } from "contracts/interfaces/external/ISwapRouter.sol";
23+
import { BytesLib } from "external/contracts/uniswap/v3/lib/BytesLib.sol";
24+
25+
import { IIndexExchangeAdapter } from "../../../interfaces/IIndexExchangeAdapter.sol";
26+
27+
/**
28+
* @title UniswapV3IndexExchangeAdapter
29+
* @author Set Protocol
30+
*
31+
* A Uniswap V3 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 UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter {
35+
36+
using BytesLib for bytes;
37+
38+
/* ============ Constants ============ */
39+
40+
// Uniswap router function string for swapping exact amount of input tokens for a minimum of output tokens
41+
string internal constant SWAP_EXACT_INPUT = "exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))";
42+
// Uniswap router function string for swapping max amoutn of input tokens for an exact amount of output tokens
43+
string internal constant SWAP_EXACT_OUTPUT = "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))";
44+
45+
/* ============ State Variables ============ */
46+
47+
// Address of Uniswap V3 SwapRouter contract
48+
address public immutable router;
49+
50+
/* ============ Constructor ============ */
51+
52+
/**
53+
* Set state variables
54+
*
55+
* @param _router Address of Uniswap V3 SwapRouter contract
56+
*/
57+
constructor(address _router) public {
58+
router = _router;
59+
}
60+
61+
/* ============ External Getter Functions ============ */
62+
63+
/**
64+
* Return calldata for trading with Uniswap V3 SwapRouter. Trade paths are created from _sourceToken,
65+
* _destinationToken and pool fees (which is encoded in _data).
66+
*
67+
* ---------------------------------------------------------------------------------------------------------------
68+
* _isSendTokenFixed | Parameter | Amount |
69+
* ---------------------------------------------------------------------------------------------------------------
70+
* True | _sourceQuantity | Fixed amount of _sourceToken to trade |
71+
* | _destinationQuantity | Minimum amount of _destinationToken willing to receive |
72+
* ---------------------------------------------------------------------------------------------------------------
73+
* False | _sourceQuantity | Maximum amount of _sourceToken to trade |
74+
* | _destinationQuantity | Fixed amount of _destinationToken want to receive |
75+
* ---------------------------------------------------------------------------------------------------------------
76+
*
77+
* @param _sourceToken Address of source token to be sold
78+
* @param _destinationToken Address of destination token to buy
79+
* @param _destinationAddress Address that assets should be transferred to
80+
* @param _isSendTokenFixed Boolean indicating if the send quantity is fixed, used to determine correct trade interface
81+
* @param _sourceQuantity Fixed/Max amount of source token to sell
82+
* @param _destinationQuantity Min/Fixed amount of destination token to buy
83+
* @param _data Arbitrary bytes containing fees value, expressed in hundredths of a bip,
84+
* used to determine the pool to trade among similar asset pools on Uniswap V3.
85+
* Note: SetToken manager must set the appropriate pool fees via `setExchangeData` in GeneralIndexModule
86+
* for each component that needs to be traded on UniswapV3. This is different from UniswapV3ExchangeAdapter,
87+
* where `_data` represents UniswapV3 trade path vs just the pool fees percentage.
88+
*
89+
* @return address Target contract address
90+
* @return uint256 Call value
91+
* @return bytes Trade calldata
92+
*/
93+
function getTradeCalldata(
94+
address _sourceToken,
95+
address _destinationToken,
96+
address _destinationAddress,
97+
bool _isSendTokenFixed,
98+
uint256 _sourceQuantity,
99+
uint256 _destinationQuantity,
100+
bytes memory _data
101+
)
102+
external
103+
view
104+
override
105+
returns (address, uint256, bytes memory)
106+
{
107+
uint24 fee = _data.toUint24(0);
108+
109+
bytes memory callData = _isSendTokenFixed
110+
? abi.encodeWithSignature(
111+
SWAP_EXACT_INPUT,
112+
ISwapRouter.ExactInputSingleParams(
113+
_sourceToken,
114+
_destinationToken,
115+
fee,
116+
_destinationAddress,
117+
block.timestamp,
118+
_sourceQuantity,
119+
_destinationQuantity,
120+
0
121+
)
122+
) : abi.encodeWithSignature(
123+
SWAP_EXACT_OUTPUT,
124+
ISwapRouter.ExactOutputSingleParams(
125+
_sourceToken,
126+
_destinationToken,
127+
fee,
128+
_destinationAddress,
129+
block.timestamp,
130+
_destinationQuantity,
131+
_sourceQuantity,
132+
0
133+
)
134+
);
135+
136+
return (router, 0, callData);
137+
}
138+
139+
/**
140+
* Returns the address to approve source tokens to for trading. This is the Uniswap V3 router address.
141+
*
142+
* @return address Address of the contract to approve tokens to
143+
*/
144+
function getSpender() external view override returns (address) {
145+
return router;
146+
}
147+
148+
/**
149+
* Helper that returns encoded fee value.
150+
*
151+
* @param fee UniswapV3 pool fee percentage, expressed in hundredths of a bip
152+
*
153+
* @return bytes Encoded fee value
154+
*/
155+
function getEncodedFeeData(uint24 fee) external view returns (bytes memory) {
156+
return abi.encodePacked(fee);
157+
}
158+
}

external/abi/uniswap/v3/SwapRouter.json

Lines changed: 7 additions & 7 deletions
Large diffs are not rendered by default.

external/contracts/uniswap/v3/UniswapV3Factory.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,4 @@ contract UniswapV3Factory is IUniswapV3Factory, UniswapV3PoolDeployer, NoDelegat
7070
feeAmountTickSpacing[fee] = tickSpacing;
7171
emit FeeAmountEnabled(fee, tickSpacing);
7272
}
73-
}
73+
}

external/contracts/uniswap/v3/lib/BytesLib.sol

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
77
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
88
*/
9-
pragma solidity >=0.5.0 <0.8.0;
9+
pragma solidity 0.6.10;
1010

1111
library BytesLib {
1212
function slice(
1313
bytes memory _bytes,
1414
uint256 _start,
1515
uint256 _length
1616
) internal pure returns (bytes memory) {
17-
require(_length + 31 >= _length, 'slice_overflow');
18-
require(_start + _length >= _start, 'slice_overflow');
19-
require(_bytes.length >= _start + _length, 'slice_outOfBounds');
17+
require(_length + 31 >= _length, "slice_overflow");
18+
require(_start + _length >= _start, "slice_overflow");
19+
require(_bytes.length >= _start + _length, "slice_outOfBounds");
2020

2121
bytes memory tempBytes;
2222

@@ -76,8 +76,8 @@ library BytesLib {
7676
}
7777

7878
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
79-
require(_start + 20 >= _start, 'toAddress_overflow');
80-
require(_bytes.length >= _start + 20, 'toAddress_outOfBounds');
79+
require(_start + 20 >= _start, "toAddress_overflow");
80+
require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
8181
address tempAddress;
8282

8383
assembly {
@@ -88,8 +88,8 @@ library BytesLib {
8888
}
8989

9090
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
91-
require(_start + 3 >= _start, 'toUint24_overflow');
92-
require(_bytes.length >= _start + 3, 'toUint24_outOfBounds');
91+
require(_start + 3 >= _start, "toUint24_overflow");
92+
require(_bytes.length >= _start + 3, "toUint24_outOfBounds");
9393
uint24 tempUint;
9494

9595
assembly {

0 commit comments

Comments
 (0)