Skip to content

Commit 658e0b6

Browse files
committed
test(arbToGno): honest claim - dishonest challenge - bridger paid, challenger deposit forfeited
1 parent 0da4c27 commit 658e0b6

File tree

1 file changed

+187
-0
lines changed

1 file changed

+187
-0
lines changed

contracts/test/integration/ArbToGnosis.ts

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,191 @@ describe("Arbitrum to Gnosis Bridge Tests", async () => {
349349
expect(finalBalance.sub(initialBalance)).to.equal(TEN_ETH, "Incorrect withdrawal amount");
350350
});
351351
});
352+
353+
describe("Honest Claim - Dishonest Challenge - Bridger paid, challenger deposit forfeited", async () => {
354+
let epoch: number;
355+
let batchMerkleRoot: string;
356+
357+
beforeEach(async () => {
358+
// Setup: Send message and save snapshot on Arbitrum
359+
await senderGateway.connect(sender).sendMessage(1121);
360+
await veaInbox.connect(bridger).saveSnapshot();
361+
362+
const BatchOutgoing = veaInbox.filters.SnapshotSaved();
363+
const batchOutGoingEvent = await veaInbox.queryFilter(BatchOutgoing);
364+
epoch = Math.floor((await batchOutGoingEvent[0].getBlock()).timestamp / EPOCH_PERIOD);
365+
batchMerkleRoot = await veaInbox.snapshots(epoch);
366+
367+
// Advance time to next epoch
368+
await network.provider.send("evm_increaseTime", [EPOCH_PERIOD]);
369+
await network.provider.send("evm_mine");
370+
371+
// Ensure bridger and challenger have enough WETH
372+
await weth.transfer(bridger.address, TEN_ETH.mul(2));
373+
await weth.transfer(challenger.address, TEN_ETH.mul(2));
374+
375+
// Approve WETH spending for both
376+
await weth.connect(bridger).approve(veaOutbox.address, TEN_ETH.mul(2));
377+
await weth.connect(challenger).approve(veaOutbox.address, TEN_ETH.mul(2));
378+
await amb.setMaxGasPerTx(100000);
379+
});
380+
381+
it("should allow challenger to submit a challenge", async () => {
382+
const { claimBlock, challengeTx } = await setupClaimAndChallenge(epoch, batchMerkleRoot, 0);
383+
384+
await expect(challengeTx).to.emit(veaOutbox, "Challenged").withArgs(epoch, challenger.address);
385+
});
386+
387+
it("should handle the entire cross-chain dispute resolution process", async () => {
388+
const { claimBlock } = await setupClaimAndChallenge(epoch, batchMerkleRoot, 0);
389+
390+
const sendSnapshotTx = await veaInbox.connect(bridger).sendSnapshot(
391+
epoch,
392+
100000,
393+
{
394+
stateRoot: batchMerkleRoot,
395+
claimer: bridger.address,
396+
timestampClaimed: claimBlock.timestamp,
397+
timestampVerification: 0,
398+
blocknumberVerification: 0,
399+
honest: 0,
400+
challenger: challenger.address,
401+
},
402+
{ gasLimit: 100000 }
403+
);
404+
405+
await expect(sendSnapshotTx)
406+
.to.emit(veaInbox, "SnapshotSent")
407+
.withArgs(epoch, ethers.utils.formatBytes32String(""));
408+
409+
await network.provider.send("evm_increaseTime", [EPOCH_PERIOD]);
410+
await network.provider.send("evm_mine");
411+
412+
const routerEvents = await router.queryFilter(router.filters.Routed(), sendSnapshotTx.blockNumber);
413+
expect(routerEvents.length).to.equal(1, "Expected one Routed event");
414+
const routedEvent = routerEvents[0];
415+
expect(routedEvent.args._epoch).to.equal(epoch, "Routed event epoch mismatch");
416+
expect(routedEvent.args._ticketID).to.not.equal(
417+
ethers.constants.HashZero,
418+
"Routed event ticketID should not be zero"
419+
);
420+
421+
// Simulate time passing for claim and challenge period
422+
await network.provider.send("evm_increaseTime", [CHALLENGE_PERIOD + SEQUENCER_DELAY]);
423+
await network.provider.send("evm_mine");
424+
425+
const events = await amb.queryFilter(amb.filters.MockedEvent());
426+
expect(events.length).to.be.above(0, "No MockedEvent emitted");
427+
428+
// Simulate the passage of time
429+
await network.provider.send("evm_increaseTime", [EPOCH_PERIOD]);
430+
await network.provider.send("evm_mine");
431+
432+
const lastEvent = events[events.length - 1];
433+
434+
await amb.executeMessageCall(
435+
veaOutbox.address,
436+
router.address,
437+
lastEvent.args._data,
438+
lastEvent.args.messageId,
439+
1000000
440+
);
441+
442+
expect(await amb.messageCallStatus(lastEvent.args.messageId)).to.be.true;
443+
444+
// Check for Verified event
445+
const verifiedEvents = await veaOutbox.queryFilter(veaOutbox.filters.Verified());
446+
expect(verifiedEvents.length).to.equal(1, "Expected one Verified event");
447+
const verifiedEvent = verifiedEvents[0];
448+
expect(verifiedEvent.args._epoch).to.equal(epoch, "Verified event epoch mismatch");
449+
450+
expect(await veaOutbox.stateRoot()).to.equal(batchMerkleRoot, "VeaOutbox stateRoot should be updated");
451+
expect(await veaOutbox.latestVerifiedEpoch()).to.equal(epoch, "VeaOutbox latestVerifiedEpoch should be updated");
452+
});
453+
454+
it("should allow bridger to withdraw deposit plus reward", async () => {
455+
const { claimBlock } = await setupClaimAndChallenge(epoch, batchMerkleRoot, 0);
456+
457+
await simulateDisputeResolution(epoch, {
458+
stateRoot: batchMerkleRoot,
459+
claimer: bridger.address,
460+
timestampClaimed: claimBlock.timestamp,
461+
timestampVerification: 0,
462+
blocknumberVerification: 0,
463+
honest: 0,
464+
challenger: challenger.address,
465+
});
466+
467+
const bridgerInitialBalance = await weth.balanceOf(bridger.address);
468+
await veaOutbox.connect(bridger).withdrawClaimDeposit(epoch, {
469+
stateRoot: batchMerkleRoot,
470+
claimer: bridger.address,
471+
timestampClaimed: claimBlock.timestamp,
472+
timestampVerification: 0,
473+
blocknumberVerification: 0,
474+
honest: 1,
475+
challenger: challenger.address,
476+
});
477+
const bridgerFinalBalance = await weth.balanceOf(bridger.address);
478+
expect(bridgerFinalBalance.sub(bridgerInitialBalance)).to.equal(
479+
TEN_ETH.add(TEN_ETH.div(2)),
480+
"Incorrect withdrawal amount"
481+
);
482+
});
483+
484+
it("should not allow challenger to withdraw deposit", async () => {
485+
const { claimBlock } = await setupClaimAndChallenge(epoch, batchMerkleRoot, 0);
486+
487+
await simulateDisputeResolution(epoch, {
488+
stateRoot: batchMerkleRoot,
489+
claimer: bridger.address,
490+
timestampClaimed: claimBlock.timestamp,
491+
timestampVerification: 0,
492+
blocknumberVerification: 0,
493+
honest: 0,
494+
challenger: challenger.address,
495+
});
496+
497+
await expect(
498+
veaOutbox.connect(challenger).withdrawChallengeDeposit(epoch, {
499+
stateRoot: batchMerkleRoot,
500+
claimer: bridger.address,
501+
timestampClaimed: claimBlock.timestamp,
502+
timestampVerification: 0,
503+
blocknumberVerification: 0,
504+
honest: 1,
505+
challenger: challenger.address,
506+
})
507+
).to.be.revertedWith("Challenge failed.");
508+
});
509+
510+
it("should allow message relay after dispute resolution", async () => {
511+
const { claimBlock } = await setupClaimAndChallenge(epoch, batchMerkleRoot, 0);
512+
513+
await simulateDisputeResolution(epoch, {
514+
stateRoot: batchMerkleRoot,
515+
claimer: bridger.address,
516+
timestampClaimed: claimBlock.timestamp,
517+
timestampVerification: 0,
518+
blocknumberVerification: 0,
519+
honest: 0,
520+
challenger: challenger.address,
521+
});
522+
523+
const MessageSent = veaInbox.filters.MessageSent();
524+
const MessageSentEvent = await veaInbox.queryFilter(MessageSent);
525+
const msg = MessageSentEvent[0].args._nodeData;
526+
const nonce = "0x" + msg.slice(2, 18);
527+
const to = "0x" + msg.slice(18, 58);
528+
const msgData = "0x" + msg.slice(58);
529+
530+
let nodes: string[] = [];
531+
nodes.push(MerkleTree.makeLeafNode(nonce, to, msgData));
532+
const mt = new MerkleTree(nodes);
533+
const proof = mt.getHexProof(nodes[0]);
534+
535+
const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, 0, receiverGateway.address, msgData);
536+
await expect(relayTx).to.emit(veaOutbox, "MessageRelayed").withArgs(0);
537+
});
538+
});
352539
});

0 commit comments

Comments
 (0)