Skip to content

Commit 59ee2b7

Browse files
authored
Robust ovm prod tests (Synthetixio#1130)
1 parent 468a28b commit 59ee2b7

File tree

4 files changed

+303
-192
lines changed

4 files changed

+303
-192
lines changed

publish/src/commands/deploy-ovm-pair.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const deployInstance = async ({ useOvm, privateKey, l1ProviderUrl, l2ProviderUrl
5959
methodCallGasLimit: '3500000',
6060
contractDeploymentGasLimit: useOvm ? OVM_MAX_GAS_LIMIT : '9500000',
6161
privateKey,
62-
ignoreCustomParameters: true,
62+
ignoreCustomParameters: false,
6363
});
6464
};
6565

test/optimism/synthExchange.test.js

+172-89
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,153 @@ const itCanPerformSynthExchange = ({ ctx }) => {
1919
ExchangerL2,
2020
ExchangeRatesL2,
2121
ExchangeStateL2,
22-
FeePoolL2;
22+
FeePoolL2,
23+
SystemSettingsL2;
2324

24-
let user1sETHBalanceL2, user1sUSDBalanceL2;
2525
// --------------------------
2626
// Setup
2727
// --------------------------
2828

29+
const itCanSettleL2 = async (canSettle, synth) => {
30+
describe('When the user tries to settle', () => {
31+
before('connect user to contract', async () => {
32+
SynthetixL2 = SynthetixL2.connect(user1L2);
33+
});
34+
if (canSettle) {
35+
it('settles correctly', async () => {
36+
const tx = await SynthetixL2.settle(synth);
37+
const receipt = await tx.wait();
38+
if (!receipt) {
39+
throw new Error(`Transaction reverted, even though it was not supposed to.`);
40+
}
41+
});
42+
} else {
43+
it('settling reverts', async () => {
44+
const tx = await SynthetixL2.settle(synth);
45+
46+
await assertRevertOptimism({
47+
tx,
48+
reason: 'Cannot settle during waiting',
49+
provider: ctx.providerL2,
50+
});
51+
});
52+
}
53+
});
54+
};
55+
56+
const itHasExchangeEntriesL2 = async numEntries => {
57+
describe('When checking ExhangeState', () => {
58+
it(`${numEntries} exchange state entries should have been created`, async () => {
59+
assert.bnEqual(
60+
await ExchangeStateL2.getLengthOfEntries(user1L2.address, sETH),
61+
numEntries
62+
);
63+
});
64+
});
65+
};
66+
67+
const itCanSetTheWaitingPeriodL2 = async waitingPeriod => {
68+
describe(`When setting the waiting period to ${waitingPeriod}`, () => {
69+
before('setWaitingPeriod', async () => {
70+
SystemSettingsL2 = SystemSettingsL2.connect(ctx.ownerL2);
71+
const tx = await SystemSettingsL2.setWaitingPeriodSecs(waitingPeriod);
72+
await tx.wait();
73+
});
74+
75+
it('waiting is set correctly', async () => {
76+
assert.bnEqual(await ExchangerL2.waitingPeriodSecs(), waitingPeriod);
77+
});
78+
});
79+
};
80+
81+
const itCanExchangeUsdToEthL2 = async sUSDtoBeExchanged => {
82+
describe('when the user exchanges sUSD for sETH', () => {
83+
let received;
84+
let normalizedFee;
85+
let feeAddresssUSDBalanceL2;
86+
let feesToDistributeL2;
87+
let user1sETHBalanceL2, user1sUSDBalanceL2;
88+
const feeAddress = getUsers({ network: 'mainnet', user: 'fee' }).address;
89+
90+
before('record current values', async () => {
91+
user1sETHBalanceL2 = await SynthsETHL2.balanceOf(user1L2.address);
92+
user1sUSDBalanceL2 = await SynthsUSDL2.balanceOf(user1L2.address);
93+
feeAddresssUSDBalanceL2 = await SynthsUSDL2.balanceOf(feeAddress);
94+
const feePeriodZero = await FeePoolL2.recentFeePeriods(0);
95+
feesToDistributeL2 = feePeriodZero.feesToDistribute;
96+
});
97+
98+
before('connect user to contract', async () => {
99+
SynthetixL2 = SynthetixL2.connect(user1L2);
100+
});
101+
102+
before('sUSD to sETH exchange', async () => {
103+
const tx = await SynthetixL2.exchange(sUSD, sUSDtoBeExchanged, sETH);
104+
await tx.wait();
105+
const { amountReceived, fee } = await ExchangerL2.getAmountsForExchange(
106+
sUSDtoBeExchanged,
107+
sUSD,
108+
sETH
109+
);
110+
received = amountReceived;
111+
normalizedFee = await ExchangeRatesL2.effectiveValue(sETH, fee, sUSD);
112+
});
113+
114+
it('shows that the user L2 sUSD balance has decreased', async () => {
115+
assert.bnEqual(
116+
await SynthsUSDL2.balanceOf(user1L2.address),
117+
user1sUSDBalanceL2.sub(sUSDtoBeExchanged)
118+
);
119+
});
120+
it('shows that the user L2 sETH balance has increased', async () => {
121+
assert.bnEqual(
122+
await SynthsETHL2.balanceOf(user1L2.address),
123+
user1sETHBalanceL2.add(received)
124+
);
125+
});
126+
it('shows that the user fees have been recorded correctly', async () => {
127+
const firstPeriod = await FeePoolL2.recentFeePeriods(0);
128+
129+
assert.bnEqual(firstPeriod.feePeriodId, '1');
130+
assert.bnEqual(firstPeriod.feesToDistribute, feesToDistributeL2.add(normalizedFee));
131+
assert.bnEqual(firstPeriod.feesClaimed, '0');
132+
});
133+
it('shows that the fees are initially remitted to the right address(0xfeEFEEfeefEeFeefEEFEEfEeFeefEEFeeFEEFEeF)', async () => {
134+
// fee remittance
135+
assert.bnEqual(
136+
await SynthsUSDL2.balanceOf(feeAddress),
137+
feeAddresssUSDBalanceL2.add(normalizedFee)
138+
);
139+
});
140+
});
141+
};
142+
143+
const itCanIssueL2 = async sUSDIssued => {
144+
describe('When the user issues sUSD', () => {
145+
let user1sETHBalanceL2, user1sUSDBalanceL2;
146+
before('connect user to contract', async () => {
147+
SynthetixL2 = SynthetixL2.connect(user1L2);
148+
});
149+
before('record current values', async () => {
150+
user1sETHBalanceL2 = await SynthsETHL2.balanceOf(user1L2.address);
151+
user1sUSDBalanceL2 = await SynthsUSDL2.balanceOf(user1L2.address);
152+
});
153+
154+
before(`issue ${sUSDIssued} sUSD`, async () => {
155+
const tx = await SynthetixL2.issueSynths(sUSDIssued);
156+
await tx.wait();
157+
});
158+
159+
it('shows that the user L2 sUSD balance has increased (while all other synth balacnes remain the same)', async () => {
160+
assert.bnEqual(
161+
await SynthsUSDL2.balanceOf(user1L2.address),
162+
user1sUSDBalanceL2.add(sUSDIssued)
163+
);
164+
assert.bnEqual(await SynthsETHL2.balanceOf(user1L2.address), user1sETHBalanceL2);
165+
});
166+
});
167+
};
168+
29169
before('identify signers', async () => {
30170
user1L1 = ctx.providerL1.getSigner(ctx.user1Address);
31171
user1L1.address = ctx.user1Address;
@@ -86,26 +226,17 @@ const itCanPerformSynthExchange = ({ ctx }) => {
86226
useOvm: true,
87227
provider: ctx.providerL2,
88228
});
229+
SystemSettingsL2 = connectContract({
230+
contract: 'SystemSettings',
231+
useOvm: true,
232+
provider: ctx.providerL2,
233+
});
89234
});
90235

91236
// --------------------------
92237
// Get SNX
93238
// --------------------------
94239

95-
describe('Initial values', () => {
96-
before('record current values', async () => {
97-
user1sETHBalanceL2 = await SynthsETHL2.balanceOf(user1L2.address);
98-
user1sUSDBalanceL2 = await SynthsETHL2.balanceOf(user1L2.address);
99-
});
100-
101-
it('the waiting period is 360 on L2', async () => {
102-
assert.bnEqual(await ExchangerL2.waitingPeriodSecs(), '300');
103-
});
104-
it('the initial sETH balance is 0', async () => {
105-
assert.bnEqual(await SynthsETHL2.balanceOf(user1L2.address), '0');
106-
});
107-
});
108-
109240
describe('when a user has the expected amount of SNX in L1', () => {
110241
let user1BalanceL1;
111242

@@ -214,80 +345,32 @@ const itCanPerformSynthExchange = ({ ctx }) => {
214345
);
215346
});
216347

217-
describe('when the user issues sUSD', () => {
348+
describe('When the waiting period is 0', () => {
349+
const sUSDIssued = ethers.utils.parseEther('10');
350+
itCanSetTheWaitingPeriodL2('0');
351+
itCanIssueL2(sUSDIssued);
352+
itCanExchangeUsdToEthL2(sUSDIssued);
353+
// since the waiting period is 0 is should skip cerating exchange entries (SIP-118)
354+
itHasExchangeEntriesL2('0');
355+
// since the waiting period is 0 it settle should not fail, it just has no effect
356+
itCanSettleL2(true, sETH);
357+
});
358+
359+
describe('When the waiting period is greater than 0', () => {
218360
const sUSDIssued = ethers.utils.parseEther('10');
219-
before('issue sUSD', async () => {
220-
SynthetixL2 = SynthetixL2.connect(user1L2);
221-
222-
const tx = await SynthetixL2.issueSynths(sUSDIssued);
223-
await tx.wait();
224-
});
225-
226-
it('shows that the user L2 sUSD balance has increased (while all other synth balacnes remain the same)', async () => {
227-
assert.bnEqual(
228-
await SynthsUSDL2.balanceOf(user1L2.address),
229-
user1sUSDBalanceL2.add(sUSDIssued)
230-
);
231-
assert.bnEqual(await SynthsETHL2.balanceOf(user1L2.address), user1sETHBalanceL2);
232-
});
233-
234-
describe('when the exchanges sUSD for sETH', () => {
235-
let received;
236-
let normalizedFee;
237-
before('sETH exchange', async () => {
238-
const tx = await SynthetixL2.exchange(sUSD, sUSDIssued, sETH);
239-
await tx.wait();
240-
const { amountReceived, fee } = await ExchangerL2.getAmountsForExchange(
241-
sUSDIssued,
242-
sUSD,
243-
sETH
244-
);
245-
received = amountReceived;
246-
normalizedFee = await ExchangeRatesL2.effectiveValue(sETH, fee, sUSD);
247-
});
248-
249-
it('shows that the user L2 sUSD balance has decreased', async () => {
250-
assert.bnEqual(
251-
await SynthsUSDL2.balanceOf(user1L2.address),
252-
user1sUSDBalanceL2
253-
);
254-
});
255-
it('shows that the user L2 sETH balance has increased', async () => {
256-
assert.bnEqual(
257-
await SynthsETHL2.balanceOf(user1L2.address),
258-
user1sETHBalanceL2.add(received)
259-
);
260-
});
261-
it('shows that the user fees have been recorded correctly', async () => {
262-
const firstPeriod = await FeePoolL2.recentFeePeriods(0);
263-
264-
assert.bnEqual(firstPeriod.feePeriodId, '1');
265-
assert.bnEqual(firstPeriod.feesToDistribute, normalizedFee);
266-
assert.bnEqual(firstPeriod.feesClaimed, '0');
267-
});
268-
it('shows that the fees are initially remitted to the right address(0xfeEFEEfeefEeFeefEEFEEfEeFeefEEFeeFEEFEeF)', async () => {
269-
// fee remittance
270-
const feeAddress = getUsers({ network: 'mainnet', user: 'fee' }).address;
271-
assert.bnEqual(await SynthsUSDL2.balanceOf(feeAddress), normalizedFee);
272-
});
273-
it('should create an exchange state entry', async () => {
274-
assert.bnEqual(
275-
await ExchangeStateL2.getLengthOfEntries(user1L2.address, sETH),
276-
'1'
277-
);
278-
});
279-
describe('when settling the exchange', () => {
280-
it('reverts when trying to settle without waiting', async () => {
281-
const tx = await SynthetixL2.settle(toBytes32('sETH'));
282-
283-
await assertRevertOptimism({
284-
tx,
285-
reason: 'Cannot settle during waiting',
286-
provider: ctx.providerL2,
287-
});
288-
});
289-
});
290-
});
361+
itCanSetTheWaitingPeriodL2('360');
362+
itCanIssueL2(sUSDIssued);
363+
itCanExchangeUsdToEthL2(sUSDIssued);
364+
// since the waiting period is gt 0 it should have created exchange entries
365+
itHasExchangeEntriesL2('1');
366+
// since the waiting period is gt 0 it should not be possible to settle immediately, hence the fist argument is false
367+
itCanSettleL2(false, sETH);
368+
// since settlement fails, the entries should persist
369+
itHasExchangeEntriesL2('1');
370+
// set the waiting period to 0
371+
itCanSetTheWaitingPeriodL2('0');
372+
// it should be able to settle now!
373+
itCanSettleL2(true, sETH);
291374
});
292375
});
293376
});

test/optimism/utils/revertOptimism.js

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
const ethers = require('ethers');
22

3+
function _hexToString(hex) {
4+
let str = '';
5+
6+
const terminator = '**zÛ';
7+
for (var i = 0; i < hex.length; i += 2) {
8+
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
9+
10+
if (str.includes(terminator)) {
11+
break;
12+
}
13+
}
14+
15+
return str.substring(0, str.length - 4);
16+
}
17+
318
async function getOptimismRevertReason({ tx, provider }) {
419
try {
520
let code = await provider.call(tx);
@@ -10,14 +25,7 @@ async function getOptimismRevertReason({ tx, provider }) {
1025
if (code.length === 64) {
1126
reason = ethers.utils.parseBytes32String(`0x${code}`);
1227
} else {
13-
reason = '';
14-
const chunks = code.match(/.{1,62}/g);
15-
chunks.map(chunk => {
16-
try {
17-
const parsed = ethers.utils.toUtf8String(`0x${chunk}00`);
18-
reason += parsed;
19-
} catch (error) {}
20-
});
28+
reason = _hexToString(`0x${code}`);
2129
}
2230

2331
return reason;

0 commit comments

Comments
 (0)