From be90d6b1c4fea53deab26ac4d3dd4ad337095e95 Mon Sep 17 00:00:00 2001 From: Anton Kovalchuk Date: Sat, 11 May 2024 13:41:54 +0200 Subject: [PATCH] check that withdrawTo doesn't allow to withdraw to stETH on L1 address --- .../optimism/L2ERC20ExtendedTokensBridge.sol | 6 ++++ .../L2ERC20ExtendedTokensBridge.unit.test.ts | 28 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/contracts/optimism/L2ERC20ExtendedTokensBridge.sol b/contracts/optimism/L2ERC20ExtendedTokensBridge.sol index b105ab94..4c77bf02 100644 --- a/contracts/optimism/L2ERC20ExtendedTokensBridge.sol +++ b/contracts/optimism/L2ERC20ExtendedTokensBridge.sol @@ -108,6 +108,11 @@ contract L2ERC20ExtendedTokensBridge is onlyNonZeroAccount(to_) onlySupportedL2Token(l2Token_) { + /// @dev L1_TOKEN_REBASABLE doesn't allow to transfer to itself. + /// To prevent stucking tokens on L1 bridge this check was added. + if (to_ == L1_TOKEN_REBASABLE) { + revert ErrorTransferToL1TokenRebasableContract(); + } _withdrawTo(l2Token_, msg.sender, to_, amount_, l1Gas_, data_); emit WithdrawalInitiated(_getL1Token(l2Token_), l2Token_, msg.sender, to_, amount_, data_); } @@ -209,4 +214,5 @@ contract L2ERC20ExtendedTokensBridge is error ErrorSenderNotEOA(); error ErrorZeroAddressL1Bridge(); + error ErrorTransferToL1TokenRebasableContract(); } diff --git a/test/optimism/L2ERC20ExtendedTokensBridge.unit.test.ts b/test/optimism/L2ERC20ExtendedTokensBridge.unit.test.ts index 794a2288..afe065cf 100644 --- a/test/optimism/L2ERC20ExtendedTokensBridge.unit.test.ts +++ b/test/optimism/L2ERC20ExtendedTokensBridge.unit.test.ts @@ -23,7 +23,7 @@ unit("Optimism:: L2ERC20ExtendedTokensBridge", ctxFactory) .test("initial state", async (ctx) => { const { l2TokenBridge, - accounts: {l1TokenBridgeEOA, l2MessengerStubEOA}, + accounts: { l1TokenBridgeEOA, l2MessengerStubEOA }, stubs: { l1TokenNonRebasable, l2TokenNonRebasable, l1TokenRebasable, l2TokenRebasable }, } = ctx; @@ -768,6 +768,32 @@ unit("Optimism:: L2ERC20ExtendedTokensBridge", ctxFactory) assert.equalBN(await l2TokenNonRebasable.totalSupply(), totalSupplyBefore); }) + .test("withdrawTo() :: sending to L1 stETH address", async (ctx) => { + const { + l2TokenBridge, + accounts: { recipient }, + stubs: { + l1TokenRebasable, + l2TokenRebasable + }, + } = ctx; + + const l1Gas = wei`1 wei`; + const data = "0xdeadbeaf"; + + await assert.revertsWith( + l2TokenBridge + .connect(recipient) + .withdrawTo( + l2TokenRebasable.address, + l1TokenRebasable.address, + 0, + l1Gas, + data), + "ErrorTransferToL1TokenRebasableContract()" + ); + }) + .test("finalizeDeposit() :: deposits disabled", async (ctx) => { const { l2TokenBridge,