@@ -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