Skip to content

Commit 52eb244

Browse files
Add wOETH donation fork tests (#2122)
* Add wOETH donation fork tests * test: add fork test for deposit/mint/withdraw/redeem. * test: add test for redeem after rebase. --------- Co-authored-by: clement-ux <[email protected]>
1 parent 466f957 commit 52eb244

File tree

2 files changed

+269
-0
lines changed

2 files changed

+269
-0
lines changed

contracts/test/_fixture.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ const simpleOETHFixture = deployments.createFixture(async () => {
8383
);
8484
const oeth = await ethers.getContractAt("OETH", oethProxy.address);
8585

86+
const cWOETHProxy = await ethers.getContract("WOETHProxy");
87+
const woeth = await ethers.getContractAt("WOETH", cWOETHProxy.address);
88+
8689
const oethHarvesterProxy = await ethers.getContract("OETHHarvesterProxy");
8790
const oethHarvester = await ethers.getContractAt(
8891
"OETHHarvester",
@@ -183,6 +186,7 @@ const simpleOETHFixture = deployments.createFixture(async () => {
183186
// OETH
184187
oethVault,
185188
oeth,
189+
woeth,
186190
nativeStakingSSVStrategy,
187191
oethDripper,
188192
oethHarvester,
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
const { expect } = require("chai");
2+
3+
const { simpleOETHFixture, createFixtureLoader } = require("./../_fixture");
4+
const { hardhatSetBalance } = require("../_fund");
5+
const { oethUnits } = require("../helpers");
6+
7+
const oethWhaleFixture = async () => {
8+
const fixture = await simpleOETHFixture();
9+
10+
const { weth, oeth, oethVault, woeth, domen } = fixture;
11+
12+
// Domen is a OETH whale
13+
await oethVault
14+
.connect(domen)
15+
.mint(weth.address, oethUnits("20000"), oethUnits("19999"));
16+
17+
await oeth.connect(domen).approve(woeth.address, oethUnits("20000"));
18+
19+
return fixture;
20+
};
21+
22+
const loadFixture = createFixtureLoader(oethWhaleFixture);
23+
24+
describe("ForkTest: wOETH", function () {
25+
this.timeout(0);
26+
27+
let fixture;
28+
beforeEach(async () => {
29+
fixture = await loadFixture();
30+
});
31+
32+
it("Should prevent total asset manipulation by donations", async () => {
33+
const { oeth, woeth, domen } = fixture;
34+
const totalAssetsBefore = await woeth.totalAssets();
35+
await oeth.connect(domen).transfer(woeth.address, oethUnits("100"));
36+
const totalAssetsAfter = await woeth.totalAssets();
37+
38+
expect(totalAssetsBefore).to.be.equal(totalAssetsAfter);
39+
});
40+
41+
it("Deposit should not be manipulated by donations", async () => {
42+
const { oeth, woeth, domen } = fixture;
43+
44+
await expect(domen).to.have.approxBalanceOf("0", woeth);
45+
46+
// Wrap some OETH
47+
await woeth.connect(domen).deposit(oethUnits("1000"), domen.address);
48+
49+
const sharePriceBeforeDonate = await woeth.convertToAssets(
50+
oethUnits("1000")
51+
);
52+
53+
// Donate some OETH
54+
oeth.connect(domen).transfer(woeth.address, oethUnits("10000"));
55+
56+
// Ensure no change in share price
57+
const sharePriceAfterDonate = await woeth.convertToAssets(
58+
oethUnits("1000")
59+
);
60+
expect(sharePriceBeforeDonate).to.approxEqual(
61+
sharePriceAfterDonate,
62+
"Price manipulation"
63+
);
64+
65+
// Wrap again
66+
await woeth.connect(domen).deposit(oethUnits("1000"), domen.address);
67+
68+
// Ensure the balance is right
69+
await expect(domen).to.have.approxBalanceOf(
70+
// 2000 * 1000 / sharePrice(1000 OETH)
71+
oethUnits("2000").mul(oethUnits("1000")).div(sharePriceAfterDonate),
72+
woeth
73+
);
74+
});
75+
76+
it("Withdraw should not be manipulated by donations", async () => {
77+
const { oeth, woeth, domen } = fixture;
78+
79+
await expect(domen).to.have.approxBalanceOf("0", woeth);
80+
await expect(domen).to.have.approxBalanceOf("20000", oeth);
81+
82+
// Wrap some OETH
83+
await woeth.connect(domen).deposit(oethUnits("3000"), domen.address);
84+
85+
const sharePriceBeforeDonate = await woeth.convertToAssets(
86+
oethUnits("1000")
87+
);
88+
89+
// Donate some OETH
90+
oeth.connect(domen).transfer(woeth.address, oethUnits("10000"));
91+
92+
// Ensure no change in share price
93+
const sharePriceAfterDonate = await woeth.convertToAssets(
94+
oethUnits("1000")
95+
);
96+
expect(sharePriceBeforeDonate).to.approxEqual(
97+
sharePriceAfterDonate,
98+
"Price manipulation"
99+
);
100+
101+
// Withdraw
102+
await woeth
103+
.connect(domen)
104+
.withdraw(
105+
await woeth.maxWithdraw(domen.address),
106+
domen.address,
107+
domen.address
108+
);
109+
110+
// Ensure balance is right
111+
await expect(domen).to.have.approxBalanceOf("10000", oeth);
112+
});
113+
114+
describe("Funds in, Funds out", async () => {
115+
it("should deposit at the correct ratio", async () => {
116+
const { oeth, woeth, domen } = fixture;
117+
118+
const totalSupply = await woeth.totalSupply();
119+
const balanceBefore = await oeth.balanceOf(domen.address);
120+
121+
// Wrap some OETH
122+
const txResponse = await woeth
123+
.connect(domen)
124+
.deposit(oethUnits("50"), domen.address);
125+
const txReceipt = await txResponse.wait();
126+
const mintedShares = txReceipt.events[2].args.shares; // 0. transfer oeth, 1. transfer woeth, 2. deposit
127+
const assetTransfered = txReceipt.events[2].args.assets; // 0. transfer oeth, 1. transfer woeth, 2. mint
128+
129+
await expect(assetTransfered).to.be.equal(oethUnits("50"));
130+
await expect(
131+
await woeth.convertToShares(assetTransfered)
132+
).to.be.approxEqual(mintedShares);
133+
await expect(woeth).to.have.a.totalSupply(totalSupply.add(mintedShares));
134+
await expect(await woeth.balanceOf(domen.address)).to.be.equal(
135+
mintedShares
136+
);
137+
await expect(await oeth.balanceOf(domen.address)).to.be.equal(
138+
balanceBefore.sub(assetTransfered)
139+
);
140+
});
141+
it("should withdraw at the correct ratio", async () => {
142+
const { oeth, woeth, domen } = fixture;
143+
// First wrap some OETH
144+
await woeth.connect(domen).deposit(oethUnits("50"), domen.address);
145+
146+
const totalSupply = await woeth.totalSupply();
147+
const balanceBefore = await oeth.balanceOf(domen.address);
148+
149+
// Then unwrap some WOETH
150+
const txResponse = await woeth
151+
.connect(domen)
152+
.withdraw(
153+
await woeth.maxWithdraw(domen.address),
154+
domen.address,
155+
domen.address
156+
);
157+
const txReceipt = await txResponse.wait();
158+
const burnedShares = txReceipt.events[2].args.shares; // 0. transfer oeth, 1. transfer woeth, 2. withdraw
159+
const assetTransfered = txReceipt.events[2].args.assets; // 0. transfer oeth, 1. transfer woeth, 2. mint
160+
161+
await expect(assetTransfered).to.be.approxEqual(oethUnits("50"));
162+
await expect(
163+
await woeth.convertToShares(assetTransfered)
164+
).to.be.approxEqual(burnedShares);
165+
await expect(woeth).to.have.a.totalSupply(totalSupply.sub(burnedShares));
166+
await expect(await woeth.balanceOf(domen.address)).to.be.equal(0);
167+
await expect(await oeth.balanceOf(domen.address)).to.be.approxEqual(
168+
balanceBefore.add(assetTransfered)
169+
);
170+
});
171+
it("should mint at the correct ratio", async () => {
172+
const { oeth, woeth, domen } = fixture;
173+
174+
const totalSupply = await woeth.totalSupply();
175+
const balanceBefore = await oeth.balanceOf(domen.address);
176+
177+
// Mint some WOETH
178+
const txResponse = await woeth
179+
.connect(domen)
180+
.mint(oethUnits("25"), domen.address);
181+
const txReceipt = await txResponse.wait();
182+
const mintedShares = txReceipt.events[2].args.shares; // 0. transfer oeth, 1. transfer woeth, 2. mint
183+
const assetTransfered = txReceipt.events[2].args.assets; // 0. transfer oeth, 1. transfer woeth, 2. mint
184+
185+
await expect(mintedShares).to.be.equal(oethUnits("25"));
186+
await expect(await woeth.convertToAssets(mintedShares)).to.be.approxEqual(
187+
assetTransfered
188+
);
189+
await expect(woeth).to.have.a.totalSupply(totalSupply.add(mintedShares));
190+
await expect(await woeth.balanceOf(domen.address)).to.be.equal(
191+
mintedShares
192+
);
193+
await expect(await oeth.balanceOf(domen.address)).to.be.equal(
194+
balanceBefore.sub(assetTransfered)
195+
);
196+
});
197+
it("should redeem at the correct ratio", async () => {
198+
const { oeth, woeth, domen } = fixture;
199+
200+
// Mint some WOETH
201+
await woeth.connect(domen).mint(oethUnits("25"), domen.address);
202+
203+
const totalSupply = await woeth.totalSupply();
204+
const balanceBefore = await oeth.balanceOf(domen.address);
205+
206+
// Redeem some WOETH
207+
const txResponse = await woeth
208+
.connect(domen)
209+
.redeem(
210+
await woeth.maxRedeem(domen.address),
211+
domen.address,
212+
domen.address
213+
);
214+
const txReceipt = await txResponse.wait();
215+
const burnedShares = txReceipt.events[2].args.shares; // 0. transfer oeth, 1. transfer woeth, 2. redeem
216+
const assetTransfered = txReceipt.events[2].args.assets; // 0. transfer oeth, 1. transfer woeth, 2. redeem
217+
218+
await expect(burnedShares).to.be.equal(oethUnits("25"));
219+
await expect(await woeth.convertToAssets(burnedShares)).to.be.approxEqual(
220+
assetTransfered
221+
);
222+
await expect(woeth).to.have.a.totalSupply(totalSupply.sub(burnedShares));
223+
await expect(await woeth.balanceOf(domen.address)).to.be.equal(0);
224+
await expect(await oeth.balanceOf(domen.address)).to.be.approxEqual(
225+
balanceBefore.add(assetTransfered)
226+
);
227+
});
228+
it("should redeem at the correct ratio after rebase", async () => {
229+
const { weth, oethVault, woeth, domen, josh } = fixture;
230+
231+
// Mint some WOETH
232+
const initialDeposit = oethUnits("50");
233+
await woeth.connect(domen).deposit(initialDeposit, domen.address);
234+
235+
const totalAssetsBefore = await woeth.totalAssets();
236+
// Rebase
237+
await hardhatSetBalance(josh.address, "250");
238+
await weth.connect(josh).deposit({ value: oethUnits("200") });
239+
await weth.connect(josh).transfer(oethVault.address, oethUnits("200"));
240+
await oethVault.rebase();
241+
242+
const totalAssetsAfter = await woeth.totalAssets();
243+
expect(totalAssetsAfter > totalAssetsBefore).to.be.true;
244+
245+
// Then unwrap some WOETH
246+
const txResponse = await woeth
247+
.connect(domen)
248+
.redeem(
249+
await woeth.maxRedeem(domen.address),
250+
domen.address,
251+
domen.address
252+
);
253+
254+
const txReceipt = await txResponse.wait();
255+
const burnedShares = txReceipt.events[2].args.shares; // 0. transfer oeth, 1. transfer woeth, 2. redeem
256+
const assetTransfered = txReceipt.events[2].args.assets; // 0. transfer oeth, 1. transfer woeth, 2. redeem
257+
258+
await expect(assetTransfered > initialDeposit);
259+
await expect(burnedShares).to.be.approxEqual(
260+
await woeth.convertToShares(assetTransfered)
261+
);
262+
await expect(domen).to.have.a.balanceOf("0", woeth);
263+
});
264+
});
265+
});

0 commit comments

Comments
 (0)