Skip to content

Commit e5efe4c

Browse files
committed
Add sushi swap trade module integration test
1 parent 9067f74 commit e5efe4c

File tree

4 files changed

+212
-5
lines changed

4 files changed

+212
-5
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import "module-alias/register";
2+
3+
import { BigNumber } from "@ethersproject/bignumber";
4+
import { ethers } from "hardhat";
5+
6+
import { Address, Bytes } from "@utils/types";
7+
import { Account } from "@utils/test/types";
8+
import { IERC20, UniswapV2Router02 } from "@typechain/index";
9+
import {
10+
SetToken,
11+
TradeModule,
12+
ManagerIssuanceHookMock,
13+
UniswapV2ExchangeAdapterV2,
14+
} from "@utils/contracts";
15+
import { ZERO } from "@utils/constants";
16+
import DeployHelper from "@utils/deploys";
17+
import {
18+
ether,
19+
bitcoin,
20+
} from "@utils/index";
21+
import {
22+
cacheBeforeEach,
23+
getAccounts,
24+
getSystemFixture,
25+
getWaffleExpect,
26+
getUniswapFixture,
27+
getForkedTokens,
28+
initializeForkedTokens,
29+
ForkedTokens
30+
} from "@utils/test/index";
31+
32+
import { SystemFixture, UniswapFixture } from "@utils/fixtures";
33+
34+
const expect = getWaffleExpect();
35+
36+
describe("SushiSwap TradeModule Integration [ @forked-mainnet ]", () => {
37+
let owner: Account;
38+
let manager: Account;
39+
40+
let deployer: DeployHelper;
41+
42+
let uniswapExchangeAdapterV2: UniswapV2ExchangeAdapterV2;
43+
let uniswapAdapterV2Name: string;
44+
45+
let setup: SystemFixture;
46+
let sushiswapSetup: UniswapFixture;
47+
let sushiswapRouter: UniswapV2Router02;
48+
let tradeModule: TradeModule;
49+
let tokens: ForkedTokens;
50+
let wbtcRate: BigNumber;
51+
52+
before(async () => {
53+
[
54+
owner,
55+
manager,
56+
] = await getAccounts();
57+
58+
59+
deployer = new DeployHelper(owner.wallet);
60+
setup = getSystemFixture(owner.address);
61+
await setup.initialize();
62+
63+
wbtcRate = ether(29);
64+
65+
sushiswapSetup = getUniswapFixture(owner.address);
66+
sushiswapRouter = sushiswapSetup.getForkedSushiswapRouter();
67+
68+
uniswapExchangeAdapterV2 = await deployer.adapters.deployUniswapV2ExchangeAdapterV2(sushiswapRouter.address);
69+
uniswapAdapterV2Name = "UNISWAPV2";
70+
71+
tradeModule = await deployer.modules.deployTradeModule(setup.controller.address);
72+
await setup.controller.addModule(tradeModule.address);
73+
74+
await setup.integrationRegistry.addIntegration(
75+
tradeModule.address,
76+
uniswapAdapterV2Name,
77+
uniswapExchangeAdapterV2.address
78+
);
79+
80+
await initializeForkedTokens(deployer);
81+
});
82+
83+
describe("#trade", function() {
84+
let sourceToken: IERC20;
85+
let wbtcUnits: BigNumber;
86+
let destinationToken: IERC20;
87+
let setToken: SetToken;
88+
let issueQuantity: BigNumber;
89+
90+
context("when trading a Default component on Sushiswap (version 2 adapter)", async () => {
91+
let mockPreIssuanceHook: ManagerIssuanceHookMock;
92+
let sourceTokenQuantity: BigNumber;
93+
let destinationTokenQuantity: BigNumber;
94+
95+
let subjectDestinationToken: Address;
96+
let subjectSourceToken: Address;
97+
let subjectSourceQuantity: BigNumber;
98+
let subjectAdapterName: string;
99+
let subjectSetToken: Address;
100+
let subjectMinDestinationQuantity: BigNumber;
101+
let subjectData: Bytes;
102+
let subjectCaller: Account;
103+
104+
cacheBeforeEach(async () => {
105+
tokens = getForkedTokens();
106+
107+
sourceToken = tokens.wbtc;
108+
destinationToken = tokens.weth;
109+
wbtcUnits = BigNumber.from(100000000); // 1 WBTC in base units 1 * 10 ** 8
110+
111+
// Create Set token
112+
setToken = await setup.createSetToken(
113+
[sourceToken.address],
114+
[wbtcUnits],
115+
[setup.issuanceModule.address, tradeModule.address],
116+
manager.address
117+
);
118+
119+
await sourceToken.approve(sushiswapRouter.address, bitcoin(100));
120+
await destinationToken.approve(sushiswapRouter.address, ether(3400));
121+
122+
tradeModule = tradeModule.connect(manager.wallet);
123+
await tradeModule.initialize(setToken.address);
124+
125+
sourceTokenQuantity = wbtcUnits;
126+
const sourceTokenDecimals = 8;
127+
destinationTokenQuantity = wbtcRate.mul(sourceTokenQuantity).div(10 ** sourceTokenDecimals);
128+
129+
// Transfer from wbtc whale to manager
130+
await sourceToken.transfer(manager.address, wbtcUnits.mul(1));
131+
132+
// Approve tokens to Controller and call issue
133+
sourceToken = sourceToken.connect(manager.wallet);
134+
await sourceToken.approve(setup.issuanceModule.address, ethers.constants.MaxUint256);
135+
136+
// Deploy mock issuance hook and initialize issuance module
137+
setup.issuanceModule = setup.issuanceModule.connect(manager.wallet);
138+
mockPreIssuanceHook = await deployer.mocks.deployManagerIssuanceHookMock();
139+
await setup.issuanceModule.initialize(setToken.address, mockPreIssuanceHook.address);
140+
141+
issueQuantity = ether(1);
142+
await setup.issuanceModule.issue(setToken.address, issueQuantity, owner.address);
143+
});
144+
145+
beforeEach(async () => {
146+
subjectSourceToken = sourceToken.address;
147+
subjectDestinationToken = destinationToken.address;
148+
subjectSourceQuantity = sourceTokenQuantity;
149+
subjectSetToken = setToken.address;
150+
subjectMinDestinationQuantity = destinationTokenQuantity.sub(ether(1)); // Receive a min of 28 WETH for 1 WBTC
151+
subjectAdapterName = uniswapAdapterV2Name;
152+
153+
const tradePath = [subjectSourceToken, subjectDestinationToken];
154+
const shouldSwapForExactToken = false;
155+
156+
subjectData = await uniswapExchangeAdapterV2.getUniswapExchangeData(
157+
tradePath,
158+
shouldSwapForExactToken
159+
);
160+
subjectCaller = manager;
161+
});
162+
163+
async function subject(): Promise<any> {
164+
tradeModule = tradeModule.connect(subjectCaller.wallet);
165+
return tradeModule.trade(
166+
subjectSetToken,
167+
subjectAdapterName,
168+
subjectSourceToken,
169+
subjectSourceQuantity,
170+
subjectDestinationToken,
171+
subjectMinDestinationQuantity,
172+
subjectData
173+
);
174+
}
175+
176+
it("should transfer the correct components to the SetToken", async () => {
177+
const oldDestinationTokenBalance = await destinationToken.balanceOf(setToken.address);
178+
const [, expectedReceiveQuantity] = await sushiswapRouter.getAmountsOut(
179+
subjectSourceQuantity,
180+
[subjectSourceToken, subjectDestinationToken]
181+
);
182+
183+
await subject();
184+
185+
const expectedDestinationTokenBalance = oldDestinationTokenBalance.add(expectedReceiveQuantity);
186+
const newDestinationTokenBalance = await destinationToken.balanceOf(setToken.address);
187+
expect(expectedReceiveQuantity).to.be.gt(ZERO);
188+
expect(newDestinationTokenBalance).to.eq(expectedDestinationTokenBalance);
189+
});
190+
191+
it("should transfer the correct components from the SetToken", async () => {
192+
const oldSourceTokenBalance = await sourceToken.balanceOf(setToken.address);
193+
194+
await subject();
195+
196+
const totalSourceQuantity = issueQuantity.mul(sourceTokenQuantity).div(ether(1));
197+
const expectedSourceTokenBalance = oldSourceTokenBalance.sub(totalSourceQuantity);
198+
const newSourceTokenBalance = await sourceToken.balanceOf(setToken.address);
199+
expect(newSourceTokenBalance).to.eq(expectedSourceTokenBalance);
200+
});
201+
});
202+
});
203+
});

test/integration/uniswapV2ExchangeTradeModule.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { SystemFixture, UniswapFixture } from "@utils/fixtures";
3333

3434
const expect = getWaffleExpect();
3535

36-
describe("UniswapExchangeV2TradeModule [ @forked-mainnet ]", () => {
36+
describe("UniswapExchangeV2 TradeModule Integration [ @forked-mainnet ]", () => {
3737
let owner: Account;
3838
let manager: Account;
3939

@@ -63,7 +63,7 @@ describe("UniswapExchangeV2TradeModule [ @forked-mainnet ]", () => {
6363
wbtcRate = ether(29);
6464

6565
uniswapSetup = getUniswapFixture(owner.address);
66-
uniswapRouter = uniswapSetup.getForkedRouterInstance();
66+
uniswapRouter = uniswapSetup.getForkedUniswapRouter();
6767

6868
uniswapExchangeAdapterV2 = await deployer.adapters.deployUniswapV2ExchangeAdapterV2(uniswapRouter.address);
6969
uniswapAdapterV2Name = "UNISWAPV2";

test/integration/zeroExExchangeTradeModule.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { SystemFixture } from "@utils/fixtures";
3131

3232
const expect = getWaffleExpect();
3333

34-
describe("ZeroExExchangeTradeModule [ @forked-mainnet ]", () => {
34+
describe("ZeroExExchange TradeModule Integration [ @forked-mainnet ]", () => {
3535
let owner: Account;
3636
let manager: Account;
3737

utils/fixtures/uniswapFixture.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@ export class UniswapFixture {
9898
return _tokenOne.toLowerCase() < _tokenTwo.toLowerCase() ? [_tokenOne, _tokenTwo] : [_tokenTwo, _tokenOne];
9999
}
100100

101-
public getForkedRouterInstance(): UniswapV2Router02 {
101+
public getForkedUniswapRouter(): UniswapV2Router02 {
102102
return this._deployer.external.getForkedUniswapV2Router02(dependencies.UNISWAP_ROUTER[1]);
103103
}
104-
}
104+
105+
public getForkedSushiswapRouter(): UniswapV2Router02 {
106+
return this._deployer.external.getForkedUniswapV2Router02(dependencies.SUSHISWAP_ROUTER[1]);
107+
}
108+
}

0 commit comments

Comments
 (0)