Skip to content

Commit 70218ec

Browse files
committed
feat: in Arbitrum bridge, revert when callhooks revert
Tickets can be retried if the L2 transaction reverts.
1 parent b80b520 commit 70218ec

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

contracts/l2/gateway/L2GraphTokenGateway.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ contract L2GraphTokenGateway is GraphTokenGateway, L2ArbitrumMessenger {
245245
// solhint-disable-next-line avoid-low-level-calls
246246
(success, ) = _to.call(callhookData);
247247
// Callhooks shouldn't revert, but if they do:
248-
// We don't want to revert if the callhook failed,
249-
// to prevent the tokens staying locked in the bridge.
248+
// we revert, so that the retryable ticket can be re-attempted
249+
// later.
250250
if (!success) {
251-
emit CallhookFailed(_to);
251+
revert("CALLHOOK_FAILED");
252252
}
253253
}
254254

test/l2/l2GraphTokenGateway.test.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -445,17 +445,30 @@ describe('L2GraphTokenGateway', () => {
445445
await testValidFinalizeTransfer(defaultDataWithNotEmptyCallHookData)
446446
expect(rewardsManagerMock.pow).to.have.been.calledWith(toBN(1), toBN(2), toBN(3))
447447
})
448-
it('performs the transfer even if a callhook reverts', async function () {
448+
it('reverts if a callhook reverts', async function () {
449449
const rewardsManagerMock = await smock.fake('RewardsManagerMock', {
450450
address: l2Receiver.address,
451451
})
452452
rewardsManagerMock.pow.reverts()
453453
await l2GraphTokenGateway
454454
.connect(governor.signer)
455455
.addToCallhookWhitelist(tokenSender.address)
456-
const tx = testValidFinalizeTransfer(defaultDataWithNotEmptyCallHookData)
457-
await expect(tx).emit(l2GraphTokenGateway, 'CallhookFailed').withArgs(l2Receiver.address)
458-
expect(rewardsManagerMock.pow).to.have.been.calledWith(toBN(1), toBN(2), toBN(3))
456+
const mockL1GatewayL2Alias = await getL2SignerFromL1(mockL1Gateway.address)
457+
await me.signer.sendTransaction({
458+
to: await mockL1GatewayL2Alias.getAddress(),
459+
value: utils.parseUnits('1', 'ether'),
460+
})
461+
const tx = l2GraphTokenGateway
462+
.connect(mockL1GatewayL2Alias)
463+
.finalizeInboundTransfer(
464+
mockL1GRT.address,
465+
tokenSender.address,
466+
l2Receiver.address,
467+
toGRT('10'),
468+
defaultDataWithNotEmptyCallHookData,
469+
)
470+
await expect(tx)
471+
.revertedWith('CALLHOOK_FAILED')
459472
})
460473
})
461474
})

0 commit comments

Comments
 (0)