Skip to content

Commit 7602794

Browse files
authored
test: token withdrawal tests using message coin (#385)
- close #274
1 parent 644a1d6 commit 7602794

File tree

6 files changed

+401
-600
lines changed

6 files changed

+401
-600
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"turbo": "^1.10.7"
4343
},
4444
"devDependencies": {
45-
"@changesets/cli": "^2.26.2",
45+
"@changesets/cli": "^2.27.11",
4646
"@fuel-ts/forc": "0.73.0"
4747
},
4848
"pnpm": {

packages/integration-tests/fork-tests/bridge_erc20.ts

+75-19
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
getBlock,
2121
FUEL_CALL_TX_PARAMS,
2222
hardhatSkipTime,
23+
fuels_parseEther,
2324
} from '@fuel-bridge/test-utils';
2425
import chai from 'chai';
2526
import { toBeHex, parseEther } from 'ethers';
@@ -32,6 +33,8 @@ import type {
3233
Provider,
3334
} from 'fuels';
3435

36+
import { fundWithdrawalTransactionWithBaseAssetResource } from '../utils/utils';
37+
3538
const { expect } = chai;
3639

3740
describe('Bridging ERC20 tokens', async function () {
@@ -61,7 +64,8 @@ describe('Bridging ERC20 tokens', async function () {
6164
fuelTokenSender: FuelWallet,
6265
ethereumTokenReceiverAddress: string,
6366
NUM_TOKENS: bigint,
64-
DECIMAL_DIFF: bigint
67+
DECIMAL_DIFF: bigint,
68+
useMessageCoin: boolean
6569
): Promise<MessageProof | null> {
6670
// withdraw tokens back to the base chain
6771
fuel_bridge.account = fuelTokenSender;
@@ -70,22 +74,19 @@ describe('Bridging ERC20 tokens', async function () {
7074
const fuelTokenSenderBalance = await fuelTokenSender.getBalance(
7175
fuel_testAssetId
7276
);
73-
const transactionRequest = await fuel_bridge.functions
74-
.withdraw(paddedAddress)
75-
.addContracts([fuel_bridge, fuel_bridgeImpl])
76-
.txParams({
77-
tip: 0,
78-
maxFee: 1,
79-
})
80-
.callParams({
81-
forward: {
82-
amount: new BN(NUM_TOKENS.toString()).div(
83-
new BN(DECIMAL_DIFF.toString())
84-
),
85-
assetId: fuel_testAssetId,
86-
},
87-
})
88-
.fundWithRequiredCoins();
77+
78+
const transactionRequest =
79+
await fundWithdrawalTransactionWithBaseAssetResource(
80+
env,
81+
fuel_bridge,
82+
fuelTokenSender,
83+
paddedAddress,
84+
NUM_TOKENS,
85+
9n,
86+
fuel_bridgeImpl,
87+
fuel_testAssetId,
88+
useMessageCoin
89+
);
8990

9091
const tx = await fuelTokenSender.sendTransaction(transactionRequest);
9192
const fWithdrawTxResult = await tx.waitForResult();
@@ -296,6 +297,59 @@ describe('Bridging ERC20 tokens', async function () {
296297
);
297298
});
298299

300+
it('Bridge ETH to Fuel to be used as Message Coin during token withdrawal', async () => {
301+
// use the FuelMessagePortal to directly send ETH which should be immediately spendable
302+
const tx = await env.eth.fuelMessagePortal
303+
.connect(ethereumTokenSender)
304+
.depositETH(fuelTokenReceiverAddress, {
305+
value: parseEther('1'),
306+
});
307+
const receipt = await tx.wait();
308+
expect(receipt.status).to.equal(1);
309+
310+
// parse events from logs
311+
const filter = env.eth.fuelMessagePortal.filters.MessageSent(
312+
null, // Args set to null since there should be just 1 event for MessageSent
313+
null,
314+
null,
315+
null,
316+
null
317+
);
318+
319+
const [event, ...restOfEvents] =
320+
await env.eth.fuelMessagePortal.queryFilter(
321+
filter,
322+
receipt.blockNumber,
323+
receipt.blockNumber
324+
);
325+
expect(restOfEvents.length).to.be.eq(0); // Should be only 1 event
326+
327+
const fuelETHMessageNonce = new BN(event.args.nonce.toString());
328+
329+
fuelTokenMessageReceiver = fuelTokenReceiver.address;
330+
331+
// wait for message to appear in fuel client
332+
expect(
333+
await waitForMessage(
334+
env.fuel.provider,
335+
fuelTokenMessageReceiver,
336+
fuelETHMessageNonce,
337+
FUEL_MESSAGE_TIMEOUT_MS
338+
)
339+
).to.not.be.null;
340+
341+
// verify the incoming messages generated when base asset is minted on fuel
342+
const incomingMessagesonFuel = await env.fuel.signers[0].getMessages();
343+
344+
// eth as bridged once at the start
345+
expect(incomingMessagesonFuel.messages.length === 1).to.be.true;
346+
347+
// 1 eth was bridged
348+
expect(
349+
incomingMessagesonFuel.messages[0].amount.eq(fuels_parseEther('1'))
350+
).to.be.true;
351+
});
352+
299353
it('Bridge ERC20 via FuelERC20Gateway', async () => {
300354
// approve FuelERC20Gateway to spend the tokens
301355
await eth_testToken
@@ -455,7 +509,8 @@ describe('Bridging ERC20 tokens', async function () {
455509
fuelTokenSender,
456510
ethereumTokenReceiverAddress,
457511
NUM_TOKENS,
458-
DECIMAL_DIFF
512+
DECIMAL_DIFF,
513+
true
459514
);
460515
});
461516

@@ -573,7 +628,8 @@ describe('Bridging ERC20 tokens', async function () {
573628
fuelTokenSender,
574629
ethereumTokenReceiverAddress,
575630
NUM_TOKENS,
576-
DECIMAL_DIFF
631+
DECIMAL_DIFF,
632+
false
577633
);
578634

579635
// relay message

packages/integration-tests/tests/bridge_erc20.ts

+76-19
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
getBlock,
2626
FUEL_CALL_TX_PARAMS,
2727
hardhatSkipTime,
28+
fuels_parseEther,
2829
} from '@fuel-bridge/test-utils';
2930
import chai from 'chai';
3031
import { toBeHex, parseEther } from 'ethers';
@@ -36,6 +37,8 @@ import type {
3637
MessageProof,
3738
} from 'fuels';
3839

40+
import { fundWithdrawalTransactionWithBaseAssetResource } from '../utils/utils';
41+
3942
const { expect } = chai;
4043

4144
describe('Bridging ERC20 tokens', async function () {
@@ -64,7 +67,8 @@ describe('Bridging ERC20 tokens', async function () {
6467
fuelTokenSender: FuelWallet,
6568
ethereumTokenReceiverAddress: string,
6669
NUM_TOKENS: bigint,
67-
DECIMAL_DIFF: bigint
70+
DECIMAL_DIFF: bigint,
71+
useMessageCoin: boolean
6872
): Promise<MessageProof> {
6973
// withdraw tokens back to the base chain
7074
fuel_bridge.account = fuelTokenSender;
@@ -73,24 +77,22 @@ describe('Bridging ERC20 tokens', async function () {
7377
const fuelTokenSenderBalance = await fuelTokenSender.getBalance(
7478
fuel_testAssetId
7579
);
76-
const transactionRequest = await fuel_bridge.functions
77-
.withdraw(paddedAddress)
78-
.addContracts([fuel_bridge, fuel_bridgeImpl])
79-
.txParams({
80-
tip: 0,
81-
maxFee: 1,
82-
})
83-
.callParams({
84-
forward: {
85-
amount: new BN(NUM_TOKENS.toString()).div(
86-
new BN(DECIMAL_DIFF.toString())
87-
),
88-
assetId: fuel_testAssetId,
89-
},
90-
})
91-
.fundWithRequiredCoins();
80+
81+
const transactionRequest =
82+
await fundWithdrawalTransactionWithBaseAssetResource(
83+
env,
84+
fuel_bridge,
85+
fuelTokenSender,
86+
paddedAddress,
87+
NUM_TOKENS,
88+
9n,
89+
fuel_bridgeImpl,
90+
fuel_testAssetId,
91+
useMessageCoin
92+
);
9293

9394
const tx = await fuelTokenSender.sendTransaction(transactionRequest);
95+
9496
const fWithdrawTxResult = await tx.waitForResult();
9597
expect(fWithdrawTxResult.status).to.equal('success');
9698

@@ -347,6 +349,59 @@ describe('Bridging ERC20 tokens', async function () {
347349
);
348350
});
349351

352+
it('Bridge ETH to Fuel to be used as Message Coin during token withdrawal', async () => {
353+
// use the FuelMessagePortal to directly send ETH which should be immediately spendable
354+
const tx = await env.eth.fuelMessagePortal
355+
.connect(ethereumTokenSender)
356+
.depositETH(fuelTokenReceiverAddress, {
357+
value: parseEther('1'),
358+
});
359+
const receipt = await tx.wait();
360+
expect(receipt.status).to.equal(1);
361+
362+
// parse events from logs
363+
const filter = env.eth.fuelMessagePortal.filters.MessageSent(
364+
null, // Args set to null since there should be just 1 event for MessageSent
365+
null,
366+
null,
367+
null,
368+
null
369+
);
370+
371+
const [event, ...restOfEvents] =
372+
await env.eth.fuelMessagePortal.queryFilter(
373+
filter,
374+
receipt.blockNumber,
375+
receipt.blockNumber
376+
);
377+
expect(restOfEvents.length).to.be.eq(0); // Should be only 1 event
378+
379+
const fuelETHMessageNonce = new BN(event.args.nonce.toString());
380+
381+
fuelTokenMessageReceiver = fuelTokenReceiver.address;
382+
383+
// wait for message to appear in fuel client
384+
expect(
385+
await waitForMessage(
386+
env.fuel.provider,
387+
fuelTokenMessageReceiver,
388+
fuelETHMessageNonce,
389+
FUEL_MESSAGE_TIMEOUT_MS
390+
)
391+
).to.not.be.null;
392+
393+
// verify the incoming messages generated when base asset is minted on fuel
394+
const incomingMessagesonFuel = await env.fuel.signers[0].getMessages();
395+
396+
// eth as bridged once at the start
397+
expect(incomingMessagesonFuel.messages.length === 1).to.be.true;
398+
399+
// 1 eth was bridged
400+
expect(
401+
incomingMessagesonFuel.messages[0].amount.eq(fuels_parseEther('1'))
402+
).to.be.true;
403+
});
404+
350405
it('Bridge ERC20 token with permit via FuelERC20Gateway', async () => {
351406
const tokenName = await eth_permitTestToken.name();
352407
const tokenAddress = await eth_permitTestToken.getAddress();
@@ -591,7 +646,8 @@ describe('Bridging ERC20 tokens', async function () {
591646
fuelTokenSender,
592647
ethereumTokenReceiverAddress,
593648
NUM_TOKENS,
594-
DECIMAL_DIFF
649+
DECIMAL_DIFF,
650+
true
595651
);
596652
});
597653

@@ -726,7 +782,8 @@ describe('Bridging ERC20 tokens', async function () {
726782
fuelTokenSender,
727783
ethereumTokenReceiverAddress,
728784
NUM_TOKENS,
729-
DECIMAL_DIFF
785+
DECIMAL_DIFF,
786+
false
730787
);
731788

732789
// relay message

0 commit comments

Comments
 (0)