1+ import "module-alias/register" ;
2+ import { BigNumber } from "@ethersproject/bignumber" ;
3+
4+ import { Address } from "@utils/types" ;
5+ import { Account } from "@utils/test/types" ;
6+ import { ADDRESS_ZERO , MAX_UINT_256 , ZERO } from "@utils/constants" ;
7+ import {
8+ GeneralIndexModule ,
9+ SetToken ,
10+ AMMSplitter ,
11+ UniswapV2IndexExchangeAdapter
12+ } from "@utils/contracts" ;
13+ import DeployHelper from "@utils/deploys" ;
14+ import {
15+ bitcoin ,
16+ ether ,
17+ preciseDiv ,
18+ preciseMul ,
19+ } from "@utils/index" ;
20+ import {
21+ cacheBeforeEach ,
22+ getAccounts ,
23+ getSystemFixture ,
24+ getUniswapFixture ,
25+ getWaffleExpect
26+ } from "@utils/test/index" ;
27+ import { SystemFixture , UniswapFixture } from "@utils/fixtures" ;
28+ import { ContractTransaction } from "ethers" ;
29+
30+ const expect = getWaffleExpect ( ) ;
31+
32+ describe ( "AMMSplitterGeneralIndexModule" , ( ) => {
33+ let owner : Account ;
34+ let trader : Account ;
35+ let positionModule : Account ;
36+ let deployer : DeployHelper ;
37+ let setup : SystemFixture ;
38+
39+ let uniswapSetup : UniswapFixture ;
40+ let sushiswapSetup : UniswapFixture ;
41+ let tradeSplitter : AMMSplitter ;
42+
43+ let index : SetToken ;
44+ let indexModule : GeneralIndexModule ;
45+
46+ let tradeSplitterAdapter : UniswapV2IndexExchangeAdapter ;
47+ let tradeSplitterAdapterName : string ;
48+
49+ let indexComponents : Address [ ] ;
50+ let indexUnits : BigNumber [ ] ;
51+
52+ before ( async ( ) => {
53+ [
54+ owner ,
55+ trader ,
56+ positionModule ,
57+ ] = await getAccounts ( ) ;
58+
59+ deployer = new DeployHelper ( owner . wallet ) ;
60+ setup = getSystemFixture ( owner . address ) ;
61+ uniswapSetup = getUniswapFixture ( owner . address ) ;
62+ sushiswapSetup = getUniswapFixture ( owner . address ) ;
63+
64+ await setup . initialize ( ) ;
65+ await uniswapSetup . initialize ( owner , setup . weth . address , setup . wbtc . address , setup . dai . address ) ;
66+ await sushiswapSetup . initialize ( owner , setup . weth . address , setup . wbtc . address , setup . dai . address ) ;
67+
68+ indexModule = await deployer . modules . deployGeneralIndexModule (
69+ setup . controller . address ,
70+ setup . weth . address
71+ ) ;
72+ await setup . controller . addModule ( indexModule . address ) ;
73+ await setup . controller . addModule ( positionModule . address ) ;
74+
75+
76+ tradeSplitter = await deployer . product . deployAMMSplitter ( uniswapSetup . router . address , sushiswapSetup . router . address ) ;
77+ tradeSplitterAdapter = await deployer . adapters . deployUniswapV2IndexExchangeAdapter ( tradeSplitter . address ) ;
78+ tradeSplitterAdapterName = "TRADESPLITTER" ;
79+
80+
81+ await setup . integrationRegistry . batchAddIntegration (
82+ [ indexModule . address ] ,
83+ [ tradeSplitterAdapterName ] ,
84+ [ tradeSplitterAdapter . address ]
85+ ) ;
86+ } ) ;
87+
88+ cacheBeforeEach ( async ( ) => {
89+ indexComponents = [ setup . wbtc . address , setup . dai . address ] ;
90+ indexUnits = [ bitcoin ( 0.01 ) , ether ( 4000 ) ] ;
91+
92+ index = await setup . createSetToken (
93+ indexComponents ,
94+ indexUnits ,
95+ [ setup . issuanceModule . address , indexModule . address , positionModule . address ] ,
96+ ) ;
97+
98+ await setup . issuanceModule . initialize ( index . address , ADDRESS_ZERO ) ;
99+ await index . connect ( positionModule . wallet ) . initializeModule ( ) ;
100+
101+ await setup . weth . connect ( owner . wallet ) . approve ( sushiswapSetup . router . address , ether ( 2000 ) ) ;
102+ await setup . dai . connect ( owner . wallet ) . approve ( sushiswapSetup . router . address , ether ( 400000 ) ) ;
103+ await sushiswapSetup . router . connect ( owner . wallet ) . addLiquidity (
104+ setup . weth . address ,
105+ setup . dai . address ,
106+ ether ( 200 ) ,
107+ ether ( 400000 ) ,
108+ ether ( 148 ) ,
109+ ether ( 173000 ) ,
110+ owner . address ,
111+ MAX_UINT_256
112+ ) ;
113+
114+ await setup . weth . connect ( owner . wallet ) . approve ( uniswapSetup . router . address , ether ( 1000 ) ) ;
115+ await setup . wbtc . connect ( owner . wallet ) . approve ( uniswapSetup . router . address , ether ( 26 ) ) ;
116+ await uniswapSetup . router . addLiquidity (
117+ setup . weth . address ,
118+ setup . wbtc . address ,
119+ ether ( 1000 ) ,
120+ bitcoin ( 25.5555 ) ,
121+ ether ( 999 ) ,
122+ ether ( 25.3 ) ,
123+ owner . address ,
124+ MAX_UINT_256
125+ ) ;
126+ } ) ;
127+
128+ describe ( "when module is initalized" , async ( ) => {
129+ let subjectSetToken : SetToken ;
130+ let subjectCaller : Account ;
131+
132+ let newComponents : Address [ ] ;
133+ let newTargetUnits : BigNumber [ ] ;
134+ let oldTargetUnits : BigNumber [ ] ;
135+ let issueAmount : BigNumber ;
136+
137+ async function initSetToken (
138+ setToken : SetToken , components : Address [ ] , tradeMaximums : BigNumber [ ] , exchanges : string [ ] , coolOffPeriods : BigNumber [ ]
139+ ) {
140+ await indexModule . initialize ( setToken . address ) ;
141+ await indexModule . setTradeMaximums ( setToken . address , components , tradeMaximums ) ;
142+ await indexModule . setExchanges ( setToken . address , components , exchanges ) ;
143+ await indexModule . setCoolOffPeriods ( setToken . address , components , coolOffPeriods ) ;
144+ await indexModule . setTraderStatus ( setToken . address , [ trader . address ] , [ true ] ) ;
145+ }
146+
147+ const startRebalance = async ( ) => {
148+ await setup . approveAndIssueSetToken ( subjectSetToken , issueAmount ) ;
149+ await indexModule . startRebalance (
150+ subjectSetToken . address ,
151+ newComponents ,
152+ newTargetUnits ,
153+ oldTargetUnits ,
154+ await index . positionMultiplier ( )
155+ ) ;
156+ } ;
157+
158+ before ( async ( ) => {
159+ newComponents = [ ] ;
160+ oldTargetUnits = [ bitcoin ( 0.1 ) , ether ( 1 ) ] ;
161+ newTargetUnits = [ ] ;
162+ issueAmount = ether ( "20.000000000000000001" ) ;
163+ } ) ;
164+
165+ cacheBeforeEach ( async ( ) => {
166+ await initSetToken (
167+ index ,
168+ [ setup . wbtc . address , setup . dai . address ] ,
169+ [ bitcoin ( 1000 ) , ether ( 100000 ) ] ,
170+ [ tradeSplitterAdapterName , tradeSplitterAdapterName ] ,
171+ [ ZERO , ZERO ]
172+ ) ;
173+ } ) ;
174+
175+ describe ( "#trade" , async ( ) => {
176+ let subjectComponent : Address ;
177+ let subjectEthQuantityLimit : BigNumber ;
178+
179+ let expectedOut : BigNumber ;
180+
181+ const initializeSubjectVariables = ( ) => {
182+ subjectSetToken = index ;
183+ subjectCaller = trader ;
184+ subjectComponent = setup . dai . address ;
185+ subjectEthQuantityLimit = ZERO ;
186+ } ;
187+
188+ async function subject ( ) : Promise < ContractTransaction > {
189+ return await indexModule . connect ( subjectCaller . wallet ) . trade (
190+ subjectSetToken . address ,
191+ subjectComponent ,
192+ subjectEthQuantityLimit
193+ ) ;
194+ }
195+
196+ describe ( "with default target units" , async ( ) => {
197+ beforeEach ( async ( ) => {
198+ initializeSubjectVariables ( ) ;
199+
200+ expectedOut = ( await tradeSplitter . getAmountsOut (
201+ preciseMul ( ether ( 3999 ) , issueAmount ) ,
202+ [ setup . dai . address , setup . weth . address ]
203+ ) ) [ 1 ] ;
204+
205+ subjectEthQuantityLimit = BigNumber . from ( 0 ) ;
206+ } ) ;
207+ cacheBeforeEach ( startRebalance ) ;
208+
209+ it ( "should sell using TradeSplitter" , async ( ) => {
210+ const currentWethAmount = await setup . weth . balanceOf ( subjectSetToken . address ) ;
211+ const totalSupply = await subjectSetToken . totalSupply ( ) ;
212+
213+ await subject ( ) ;
214+
215+ const expectedWethPositionUnits = preciseDiv ( currentWethAmount . add ( expectedOut ) , totalSupply ) ;
216+ const expectedDaiPositionUnits = ether ( 1 ) ;
217+
218+ const wethPositionUnits = await subjectSetToken . getDefaultPositionRealUnit ( setup . weth . address ) ;
219+ const daiPositionUnits = await subjectSetToken . getDefaultPositionRealUnit ( setup . dai . address ) ;
220+
221+ expect ( wethPositionUnits ) . to . eq ( expectedWethPositionUnits ) ;
222+ expect ( daiPositionUnits ) . to . eq ( expectedDaiPositionUnits ) ;
223+ } ) ;
224+ } ) ;
225+ } ) ;
226+
227+ describe ( "#tradeRemainingWETH" , async ( ) => {
228+
229+ let subjectComponent : Address ;
230+ let subjectEthQuantityLimit : BigNumber ;
231+
232+ let expectedOut : BigNumber ;
233+
234+ const initializeSubjectVariables = ( ) => {
235+ subjectSetToken = index ;
236+ subjectCaller = trader ;
237+ subjectComponent = setup . dai . address ;
238+ subjectEthQuantityLimit = ZERO ;
239+ } ;
240+
241+ async function subject ( ) : Promise < ContractTransaction > {
242+ return await indexModule . connect ( subjectCaller . wallet ) . tradeRemainingWETH (
243+ subjectSetToken . address ,
244+ subjectComponent ,
245+ subjectEthQuantityLimit
246+ ) ;
247+ }
248+
249+ describe ( "with default target units" , async ( ) => {
250+
251+ beforeEach ( async ( ) => {
252+ initializeSubjectVariables ( ) ;
253+ } ) ;
254+ cacheBeforeEach ( startRebalance ) ;
255+
256+ context ( "when it is the last trade" , async ( ) => {
257+
258+ beforeEach ( async ( ) => {
259+ await indexModule . connect ( subjectCaller . wallet ) . trade (
260+ subjectSetToken . address ,
261+ subjectComponent ,
262+ subjectEthQuantityLimit
263+ ) ;
264+
265+ expectedOut = ( await tradeSplitter . getAmountsOut (
266+ await setup . weth . balanceOf ( subjectSetToken . address ) ,
267+ [ setup . weth . address , setup . wbtc . address ]
268+ ) ) [ 1 ] ;
269+
270+ subjectComponent = setup . wbtc . address ;
271+ subjectEthQuantityLimit = ZERO ;
272+ } ) ;
273+
274+ it ( "should buy using TradeSplitter" , async ( ) => {
275+ const currentWbtcAmount = await setup . wbtc . balanceOf ( subjectSetToken . address ) ;
276+ const totalSupply = await subjectSetToken . totalSupply ( ) ;
277+
278+ await subject ( ) ;
279+
280+ const expectedWbtcPositionUnits = preciseDiv ( currentWbtcAmount . add ( expectedOut ) , totalSupply ) ;
281+ const expectedWethPositionUnits = ether ( 0 ) ;
282+
283+ const wethPositionUnits = await subjectSetToken . getDefaultPositionRealUnit ( setup . weth . address ) ;
284+ const wbtcPositionUnits = await subjectSetToken . getDefaultPositionRealUnit ( setup . wbtc . address ) ;
285+
286+ expect ( wbtcPositionUnits ) . to . eq ( expectedWbtcPositionUnits ) ;
287+ expect ( wethPositionUnits ) . to . eq ( expectedWethPositionUnits ) ;
288+ } ) ;
289+ } ) ;
290+ } ) ;
291+ } ) ;
292+ } ) ;
293+ } ) ;
0 commit comments