From 2bd626aa8481c314f8ab209e9ee5c6f2771b1d66 Mon Sep 17 00:00:00 2001 From: hexshire Date: Tue, 16 Jul 2024 16:29:49 -0300 Subject: [PATCH 01/23] fix: stop incomming messages --- src/contracts/L1OpUSDCBridgeAdapter.sol | 8 +++++--- src/contracts/L2OpUSDCBridgeAdapter.sol | 3 +++ src/contracts/universal/OpUSDCBridgeAdapter.sol | 3 +++ src/interfaces/IOpUSDCBridgeAdapter.sol | 11 +++++++++++ test/integration/L1OpUSDCBridgeAdapter.t.sol | 6 ++++-- test/unit/L1OpUSDCBridgeAdapter.t.sol | 17 +++++++++++++++++ test/unit/L2OpUSDCBridgeAdapter.t.sol | 17 +++++++++++++++++ 7 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index 874fa6e9..579d0924 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -129,6 +129,7 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { } burnCaller = address(0); + isMigrated = true; emit MigrationComplete(); } @@ -254,11 +255,12 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { /** * @notice Receive the message from the other chain and transfer the tokens to the user - * @dev This function should only be called when receiving a message to mint the bridged representation - * @param _user The user to mint the bridged representation for - * @param _amount The amount of tokens to mint + * @dev This function should only be called when receiving a message to trasnfer the tokens + * @param _user The user to transfer the tokens to + * @param _amount The amount of tokens to transfer */ function receiveMessage(address _user, uint256 _amount) external override onlyLinkedAdapter { + if (isMigrated) revert IOpUSDCBridgeAdapter_Migrated(); // Transfer the tokens to the user IUSDC(USDC).safeTransfer(_user, _amount); emit MessageReceived(_user, _amount, MESSENGER); diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 0fe91444..50ba3ac5 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -84,6 +84,8 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { LINKED_ADAPTER, abi.encodeWithSignature('setBurnAmount(uint256)', _burnAmount), _setBurnAmountMinGasLimit ); + isMigrated = true; + emit MigratingToNative(MESSENGER, _roleCaller); } @@ -207,6 +209,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @param _amount The amount of tokens to mint */ function receiveMessage(address _user, uint256 _amount) external override onlyLinkedAdapter { + if (isMigrated) revert IOpUSDCBridgeAdapter_Migrated(); // Mint the tokens to the user IUSDC(USDC).mint(_user, _amount); emit MessageReceived(_user, _amount, MESSENGER); diff --git a/src/contracts/universal/OpUSDCBridgeAdapter.sol b/src/contracts/universal/OpUSDCBridgeAdapter.sol index 5d036e6b..441388e0 100644 --- a/src/contracts/universal/OpUSDCBridgeAdapter.sol +++ b/src/contracts/universal/OpUSDCBridgeAdapter.sol @@ -22,6 +22,9 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { /// @inheritdoc IOpUSDCBridgeAdapter mapping(address _user => uint256 _nonce) public userNonce; + /// @inheritdoc IOpUSDCBridgeAdapter + bool public isMigrated; + /** * @notice Construct the OpUSDCBridgeAdapter contract * @param _usdc The address of the USDC Contract to be used by the adapter diff --git a/src/interfaces/IOpUSDCBridgeAdapter.sol b/src/interfaces/IOpUSDCBridgeAdapter.sol index 4118e0b1..5c874001 100644 --- a/src/interfaces/IOpUSDCBridgeAdapter.sol +++ b/src/interfaces/IOpUSDCBridgeAdapter.sol @@ -108,6 +108,11 @@ interface IOpUSDCBridgeAdapter { */ error IOpUSDCBridgeAdapter_BlacklistedAddress(); + /** + * @notice Error when bridgedUSDC has already been migrated to native USDC + */ + error IOpUSDCBridgeAdapter_Migrated(); + /*/////////////////////////////////////////////////////////////// LOGIC ///////////////////////////////////////////////////////////////*/ @@ -176,4 +181,10 @@ interface IOpUSDCBridgeAdapter { * @return _nonce The nonce of the user */ function userNonce(address _user) external view returns (uint256 _nonce); + + /** + * @notice Fetches whether bridged USDC has been migrated to native USDC + * @return _isMigrated Whether bridged USDC has been migrated to native USDC + */ + function isMigrated() external view returns (bool _isMigrated); } diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index c19bc103..aa9b28a3 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -189,7 +189,8 @@ contract Integration_Migration is IntegrationBase { uint256 _burnAmount = bridgedUSDC.totalSupply(); - assertEq(l2Adapter.isMessagingDisabled(), true); + assert(l2Adapter.isMigrated()); + assert(l2Adapter.isMessagingDisabled()); assertEq(l2Adapter.roleCaller(), _circle); vm.prank(_circle); @@ -213,6 +214,7 @@ contract Integration_Migration is IntegrationBase { vm.prank(_circle); l1Adapter.burnLockedUSDC(); + assert(l1Adapter.isMigrated()); assertEq(MAINNET_USDC.balanceOf(address(l1Adapter)), 0); assertEq(l1Adapter.burnAmount(), 0); assertEq(l1Adapter.burnCaller(), address(0)); @@ -244,7 +246,7 @@ contract Integration_Integration_PermissionedFlows is IntegrationBase { abi.encodeWithSignature('receiveStopMessaging()') ); - assertEq(l2Adapter.isMessagingDisabled(), true); + assert(l2Adapter.isMessagingDisabled()); vm.selectFork(mainnet); diff --git a/test/unit/L1OpUSDCBridgeAdapter.t.sol b/test/unit/L1OpUSDCBridgeAdapter.t.sol index d97975c7..f83e5058 100644 --- a/test/unit/L1OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L1OpUSDCBridgeAdapter.t.sol @@ -24,6 +24,10 @@ contract ForTestL1OpUSDCBridgeAdapter is L1OpUSDCBridgeAdapter { function forTest_setMessengerStatus(Status _status) external { messengerStatus = _status; } + + function forTest_setIsMigrated(bool _isMigrated) external { + isMigrated = _isMigrated; + } } abstract contract Base is Helpers { @@ -961,6 +965,19 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { adapter.receiveMessage(_user, _amount); } + /** + * @notice Check that the function reverts if the contract is migrated to native + */ + function test_revertIfMigratedToNative(uint256 _amount) external { + adapter.forTest_setIsMigrated(true); + // Mock calls + vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); + // Execute + vm.prank(_messenger); + vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); + adapter.receiveMessage(_user, _amount); + } + /** * @notice Check that token transfer is called as expected */ diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index 20fa8239..30e8f0c7 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -23,6 +23,10 @@ contract ForTestL2OpUSDCBridgeAdapter is L2OpUSDCBridgeAdapter { function forTest_setRoleCaller(address _roleCaller) external { roleCaller = _roleCaller; } + + function forTest_setIsMigrated(bool _isMigrated) external { + isMigrated = _isMigrated; + } } abstract contract Base is Helpers { @@ -605,6 +609,19 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { adapter.receiveMessage(_user, _amount); } + /** + * @notice Check that the function reverts if the contract is migrated to native + */ + function test_revertIfMigratedToNative(uint256 _amount) external { + adapter.forTest_setIsMigrated(true); + // Mock calls + vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); + // Execute + vm.prank(_messenger); + vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); + adapter.receiveMessage(_user, _amount); + } + /** * @notice Check that the token minting works as expected */ From aa963eacd6a89acb60ca493dd93702439b535cc3 Mon Sep 17 00:00:00 2001 From: Hex <165055168+hexshire@users.noreply.github.com> Date: Tue, 16 Jul 2024 23:49:11 -0300 Subject: [PATCH 02/23] fix: comment Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> --- src/contracts/L1OpUSDCBridgeAdapter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index 4a511506..da972f11 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -254,7 +254,7 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { /** * @notice Receive the message from the other chain and transfer the tokens to the user - * @dev This function should only be called when receiving a message to trasnfer the tokens + * @dev This function should only be called when receiving a message to transfer the tokens * @param _user The user to transfer the tokens to * @param _amount The amount of tokens to transfer */ From cccad1f2a5a68cd57bacd8f78d00402652db1293 Mon Sep 17 00:00:00 2001 From: hexshire Date: Tue, 16 Jul 2024 23:53:31 -0300 Subject: [PATCH 03/23] refactor: remove migrated check from l1 adapter --- src/contracts/L1OpUSDCBridgeAdapter.sol | 1 - src/contracts/L2OpUSDCBridgeAdapter.sol | 3 +++ src/contracts/universal/OpUSDCBridgeAdapter.sol | 3 --- src/interfaces/IL2OpUSDCBridgeAdapter.sol | 6 ++++++ src/interfaces/IOpUSDCBridgeAdapter.sol | 6 ------ test/integration/L1OpUSDCBridgeAdapter.t.sol | 1 - test/unit/L1OpUSDCBridgeAdapter.t.sol | 17 ----------------- 7 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index da972f11..ddda970a 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -259,7 +259,6 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @param _amount The amount of tokens to transfer */ function receiveMessage(address _user, uint256 _amount) external override onlyLinkedAdapter { - if (isMigrated) revert IOpUSDCBridgeAdapter_Migrated(); // Transfer the tokens to the user IUSDC(USDC).safeTransfer(_user, _amount); emit MessageReceived(_user, _amount, MESSENGER); diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 50ba3ac5..0bde949a 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -33,6 +33,9 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { /// @inheritdoc IL2OpUSDCBridgeAdapter bool public isMessagingDisabled; + /// @inheritdoc IL2OpUSDCBridgeAdapter + bool public isMigrated; + /// @inheritdoc IL2OpUSDCBridgeAdapter address public roleCaller; diff --git a/src/contracts/universal/OpUSDCBridgeAdapter.sol b/src/contracts/universal/OpUSDCBridgeAdapter.sol index 441388e0..5d036e6b 100644 --- a/src/contracts/universal/OpUSDCBridgeAdapter.sol +++ b/src/contracts/universal/OpUSDCBridgeAdapter.sol @@ -22,9 +22,6 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { /// @inheritdoc IOpUSDCBridgeAdapter mapping(address _user => uint256 _nonce) public userNonce; - /// @inheritdoc IOpUSDCBridgeAdapter - bool public isMigrated; - /** * @notice Construct the OpUSDCBridgeAdapter contract * @param _usdc The address of the USDC Contract to be used by the adapter diff --git a/src/interfaces/IL2OpUSDCBridgeAdapter.sol b/src/interfaces/IL2OpUSDCBridgeAdapter.sol index d75f04bb..86a1da5d 100644 --- a/src/interfaces/IL2OpUSDCBridgeAdapter.sol +++ b/src/interfaces/IL2OpUSDCBridgeAdapter.sol @@ -61,6 +61,12 @@ interface IL2OpUSDCBridgeAdapter { */ function isMessagingDisabled() external view returns (bool _isMessagingDisabled); + /** + * @notice Fetches whether bridged USDC has been migrated to native USDC + * @return _isMigrated Whether bridged USDC has been migrated to native USDC + */ + function isMigrated() external view returns (bool _isMigrated); + /** * @notice Fetches the address of the role caller * @return _roleCaller The address of the role caller diff --git a/src/interfaces/IOpUSDCBridgeAdapter.sol b/src/interfaces/IOpUSDCBridgeAdapter.sol index 5c874001..74064d07 100644 --- a/src/interfaces/IOpUSDCBridgeAdapter.sol +++ b/src/interfaces/IOpUSDCBridgeAdapter.sol @@ -181,10 +181,4 @@ interface IOpUSDCBridgeAdapter { * @return _nonce The nonce of the user */ function userNonce(address _user) external view returns (uint256 _nonce); - - /** - * @notice Fetches whether bridged USDC has been migrated to native USDC - * @return _isMigrated Whether bridged USDC has been migrated to native USDC - */ - function isMigrated() external view returns (bool _isMigrated); } diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index aa9b28a3..fe713579 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -214,7 +214,6 @@ contract Integration_Migration is IntegrationBase { vm.prank(_circle); l1Adapter.burnLockedUSDC(); - assert(l1Adapter.isMigrated()); assertEq(MAINNET_USDC.balanceOf(address(l1Adapter)), 0); assertEq(l1Adapter.burnAmount(), 0); assertEq(l1Adapter.burnCaller(), address(0)); diff --git a/test/unit/L1OpUSDCBridgeAdapter.t.sol b/test/unit/L1OpUSDCBridgeAdapter.t.sol index b900df84..3ed0debb 100644 --- a/test/unit/L1OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L1OpUSDCBridgeAdapter.t.sol @@ -24,10 +24,6 @@ contract ForTestL1OpUSDCBridgeAdapter is L1OpUSDCBridgeAdapter { function forTest_setMessengerStatus(Status _status) external { messengerStatus = _status; } - - function forTest_setIsMigrated(bool _isMigrated) external { - isMigrated = _isMigrated; - } } abstract contract Base is Helpers { @@ -964,19 +960,6 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { adapter.receiveMessage(_user, _amount); } - /** - * @notice Check that the function reverts if the contract is migrated to native - */ - function test_revertIfMigratedToNative(uint256 _amount) external { - adapter.forTest_setIsMigrated(true); - // Mock calls - vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); - // Execute - vm.prank(_messenger); - vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); - adapter.receiveMessage(_user, _amount); - } - /** * @notice Check that token transfer is called as expected */ From 1695ed4ab0c87b5015f61692ee34d62d1ad70a67 Mon Sep 17 00:00:00 2001 From: hexshire Date: Tue, 16 Jul 2024 23:55:02 -0300 Subject: [PATCH 04/23] refactor: follow cei pattern --- src/contracts/L2OpUSDCBridgeAdapter.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 0bde949a..8231ce84 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -79,6 +79,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { */ function receiveMigrateToNative(address _roleCaller, uint32 _setBurnAmountMinGasLimit) external onlyLinkedAdapter { isMessagingDisabled = true; + isMigrated = true; roleCaller = _roleCaller; uint256 _burnAmount = IUSDC(USDC).totalSupply(); @@ -87,8 +88,6 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { LINKED_ADAPTER, abi.encodeWithSignature('setBurnAmount(uint256)', _burnAmount), _setBurnAmountMinGasLimit ); - isMigrated = true; - emit MigratingToNative(MESSENGER, _roleCaller); } From 5d0a4de83517ccabd1fb8f62ffd7ae04e60440c4 Mon Sep 17 00:00:00 2001 From: hexshire Date: Tue, 23 Jul 2024 20:48:28 -0300 Subject: [PATCH 05/23] refactor: block update master minter function --- src/contracts/L2OpUSDCBridgeAdapter.sol | 7 +++++- test/integration/L2OpUSDCBridgeAdapter.t.sol | 23 -------------------- test/unit/L2OpUSDCBridgeAdapter.t.sol | 11 ++++++++++ 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index f70d712e..88e33354 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -26,6 +26,8 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { bytes4 internal constant _UPGRADE_TO_SELECTOR = 0x3659cfe6; ///@notice `upgradeToAndCall(address,bytes)` USDC function selector bytes4 internal constant _UPGRADE_TO_AND_CALL_SELECTOR = 0x4f1ef286; + ///@notice `updateMasterMinter(address)` USDC function selector + bytes4 internal constant _UPDATE_MASTER_MINTER_SELECTOR = 0xaa20e1e4; /// @inheritdoc IL2OpUSDCBridgeAdapter FallbackProxyAdmin public immutable FALLBACK_PROXY_ADMIN; @@ -266,7 +268,10 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { bytes4 _selector = bytes4(_data); bool _success; - if (_selector == _TRANSFER_OWNERSHIP_SELECTOR || _selector == _CHANGE_ADMIN_SELECTOR) { + if ( + _selector == _TRANSFER_OWNERSHIP_SELECTOR || _selector == _CHANGE_ADMIN_SELECTOR + || _selector == _UPDATE_MASTER_MINTER_SELECTOR + ) { revert IOpUSDCBridgeAdapter_ForbiddenTransaction(); } else if (_selector == _UPGRADE_TO_SELECTOR || _selector == _UPGRADE_TO_AND_CALL_SELECTOR) { (_success,) = address(FALLBACK_PROXY_ADMIN).call(_data); diff --git a/test/integration/L2OpUSDCBridgeAdapter.t.sol b/test/integration/L2OpUSDCBridgeAdapter.t.sol index 3fad489f..22538a18 100644 --- a/test/integration/L2OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L2OpUSDCBridgeAdapter.t.sol @@ -300,29 +300,6 @@ contract Integration_PermissionedUsdcFlows is IntegrationBase { assertEq(_pauser, _notOwner); } - /** - * @notice Test `updateMasterMinter` USDC function on L2 - */ - function test_UpdateMasterMinter() public { - // Setup necessary data - bytes memory _calldata = abi.encodeWithSignature('updateMasterMinter(address)', _notOwner); - - // Use L2OpUSDCBridgeAdapter owner to call `updateMasterMinter` function through the adapter - vm.startPrank(_owner); - - // Call `updateMasterMinter` function - l2Adapter.callUsdcTransaction(_calldata); - - //Call masterMinter function to get the masterMinter - (, bytes memory _data) = address(bridgedUSDC).call(abi.encodeWithSignature('masterMinter()')); - - //Get masterMinter from _data - address _masterMinter = address(uint160(uint256(bytes32(_data)))); - - // Check that the USDC masterMinter has been updated - assertEq(_masterMinter, _notOwner); - } - /** * @notice Test `updateBlacklister` USDC function on L2 */ diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index d5efc56f..419fb883 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -799,6 +799,17 @@ contract L2OpUSDCBridgeAdapter_Unit_CallUsdcTransaction is Base { adapter.callUsdcTransaction(_data); } + /** + * @notice Check that the function reverts function selector is updateMasterMinter (0xaa20e1e4) + */ + function test_revertIfTxIsUpdateMasterMinter(bytes memory _data) external { + _data = bytes.concat(bytes4(0xaa20e1e4), _data); + // Execute + vm.prank(_owner); + vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_ForbiddenTransaction.selector); + adapter.callUsdcTransaction(_data); + } + /** * @notice Check that the function upgradeTo gets called through the fallback admin */ From 71feceeafc7a136fced13e6607dfe01f81f02d10 Mon Sep 17 00:00:00 2001 From: hexshire Date: Tue, 23 Jul 2024 22:19:38 -0300 Subject: [PATCH 06/23] refactor: remove master minter --- src/contracts/L2OpUSDCBridgeAdapter.sol | 3 +++ src/interfaces/external/IUSDC.sol | 7 +++++++ test/unit/L2OpUSDCBridgeAdapter.t.sol | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 88e33354..c629ccc3 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -89,6 +89,9 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // But the native token is still locked on L1 uint256 _burnAmount = IUSDC(USDC).totalSupply(); + // Remove the L2 Adapter as a minter + IUSDC(USDC).removeMinter(address(this)); + ICrossDomainMessenger(MESSENGER).sendMessage( LINKED_ADAPTER, abi.encodeWithSignature('setBurnAmount(uint256)', _burnAmount), _setBurnAmountMinGasLimit ); diff --git a/src/interfaces/external/IUSDC.sol b/src/interfaces/external/IUSDC.sol index 9a74847b..d3a85892 100644 --- a/src/interfaces/external/IUSDC.sol +++ b/src/interfaces/external/IUSDC.sol @@ -62,6 +62,13 @@ interface IUSDC is IERC20 { */ function configureMinter(address _minter, uint256 _minterAllowedAmount) external returns (bool _result); + /** + * @notice Removes a minter. + * @param _minter The address of the minter to remove. + * @return _result True if the operation was successful. + */ + function removeMinter(address _minter) external returns (bool _result); + /** * @notice Updates the master minter address. * @param _newMasterMinter The address of the new master minter. diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index 419fb883..8baf93f6 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -109,6 +109,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMigrateToNative is Base { vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); _mockAndExpect(_usdc, abi.encodeWithSignature('totalSupply()'), abi.encode(_burnAmount)); + _mockAndExpect(_usdc, abi.encodeWithSignature('removeMinter(address)', adapter), abi.encode(true)); _mockAndExpect( _messenger, abi.encodeWithSignature( @@ -130,6 +131,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMigrateToNative is Base { vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); _mockAndExpect(_usdc, abi.encodeWithSignature('totalSupply()'), abi.encode(100)); + _mockAndExpect(_usdc, abi.encodeWithSignature('removeMinter(address)', adapter), abi.encode(true)); _mockAndExpect( _messenger, abi.encodeWithSignature( @@ -157,6 +159,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMigrateToNative is Base { vm.mockCall(_usdc, abi.encodeWithSignature('transferOwnership(address)', _roleCaller), abi.encode()); vm.mockCall(_usdc, abi.encodeWithSignature('changeAdmin(address)', _roleCaller), abi.encode()); vm.mockCall(_usdc, abi.encodeWithSignature('totalSupply()'), abi.encode(_burnAmount)); + vm.mockCall(_usdc, abi.encodeWithSignature('removeMinter(address)', adapter), abi.encode(true)); vm.mockCall( _messenger, abi.encodeWithSignature( From 43e52f19b6e8d25f86ecbd52efa8e14e5a7192d0 Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 11:31:53 -0300 Subject: [PATCH 07/23] test: integration test --- test/integration/L1OpUSDCBridgeAdapter.t.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index 0bded701..f48e25ee 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -222,6 +222,7 @@ contract Integration_Migration is IntegrationBase { assert(l2Adapter.isMigrated()); assert(l2Adapter.isMessagingDisabled()); assertEq(l2Adapter.roleCaller(), _circle); + assertEq(bridgedUSDC.isMinter(address(l2Adapter)), false); vm.prank(_circle); l2Adapter.transferUSDCRoles(_circle); From 8133a7a61f7809f1bb82ff9f45e03f1daff175b3 Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 12:23:32 -0300 Subject: [PATCH 08/23] refactor: use enum for l2 adapter --- src/contracts/L1OpUSDCBridgeAdapter.sol | 3 - src/contracts/L2OpUSDCBridgeAdapter.sol | 60 ++++++++----------- .../universal/OpUSDCBridgeAdapter.sol | 3 + src/interfaces/IL1OpUSDCBridgeAdapter.sol | 24 -------- src/interfaces/IL2OpUSDCBridgeAdapter.sol | 11 ---- src/interfaces/IOpUSDCBridgeAdapter.sol | 23 +++++++ test/integration/L1OpUSDCBridgeAdapter.t.sol | 17 +++--- test/unit/L1OpUSDCBridgeAdapter.t.sol | 54 ++++++++--------- test/unit/L2OpUSDCBridgeAdapter.t.sol | 46 ++++++++------ 9 files changed, 115 insertions(+), 126 deletions(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index db23dbcb..d25f7fe0 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -24,9 +24,6 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { /// @inheritdoc IL1OpUSDCBridgeAdapter address public burnCaller; - /// @inheritdoc IL1OpUSDCBridgeAdapter - Status public messengerStatus; - /** * @notice Modifier to check if the sender is the linked adapter through the messenger */ diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 49e66808..253c92aa 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -34,12 +34,6 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { /// @inheritdoc IL2OpUSDCBridgeAdapter FallbackProxyAdmin public immutable FALLBACK_PROXY_ADMIN; - /// @inheritdoc IL2OpUSDCBridgeAdapter - bool public isMessagingDisabled; - - /// @inheritdoc IL2OpUSDCBridgeAdapter - bool public isMigrated; - /// @inheritdoc IL2OpUSDCBridgeAdapter address public roleCaller; @@ -82,8 +76,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @param _setBurnAmountMinGasLimit Minimum gas limit that the setBurnAmount message can be executed on L1 */ function receiveMigrateToNative(address _roleCaller, uint32 _setBurnAmountMinGasLimit) external onlyLinkedAdapter { - isMessagingDisabled = true; - isMigrated = true; + messengerStatus = Status.Deprecated; roleCaller = _roleCaller; // We need to do totalSupply + blacklistedFunds @@ -124,7 +117,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @notice Receive the stop messaging message from the linked adapter and stop outgoing messages */ function receiveStopMessaging() external onlyLinkedAdapter { - isMessagingDisabled = true; + messengerStatus = Status.Paused; emit MessagingStopped(MESSENGER); } @@ -134,7 +127,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { */ function receiveResumeMessaging() external onlyLinkedAdapter { // NOTE: This is safe because this message can only be received when messaging is not deprecated on the L1 messenger - isMessagingDisabled = false; + messengerStatus = Status.Active; emit MessagingResumed(MESSENGER); } @@ -154,19 +147,9 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { if (IUSDC(USDC).isBlacklisted(_to)) revert IOpUSDCBridgeAdapter_BlacklistedAddress(); // Ensure messaging is enabled - if (isMessagingDisabled) revert IOpUSDCBridgeAdapter_MessagingDisabled(); - - IUSDC(USDC).safeTransferFrom(msg.sender, address(this), _amount); - - // Burn the tokens - IUSDC(USDC).burn(_amount); - - // Send the message to the linked adapter - ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit - ); + if (messengerStatus != Status.Active) revert IOpUSDCBridgeAdapter_MessagingDisabled(); - emit MessageSent(msg.sender, _to, _amount, MESSENGER, _minGasLimit); + _sendMessage(msg.sender, _to, _amount, _minGasLimit); } /** @@ -192,7 +175,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { if (IUSDC(USDC).isBlacklisted(_to)) revert IOpUSDCBridgeAdapter_BlacklistedAddress(); // Ensure messaging is enabled - if (isMessagingDisabled) revert IOpUSDCBridgeAdapter_MessagingDisabled(); + if (messengerStatus != Status.Active) revert IOpUSDCBridgeAdapter_MessagingDisabled(); // Ensure the nonce has not already been used if (userNonces[_signer][_nonce]) revert IOpUSDCBridgeAdapter_InvalidNonce(); @@ -209,17 +192,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Mark the nonce as used userNonces[_signer][_nonce] = true; - IUSDC(USDC).safeTransferFrom(_signer, address(this), _amount); - - // Burn the tokens - IUSDC(USDC).burn(_amount); - - // Send the message to the linked adapter - ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit - ); - - emit MessageSent(_signer, _to, _amount, MESSENGER, _minGasLimit); + _sendMessage(_signer, _to, _amount, _minGasLimit); } /** @@ -229,7 +202,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @param _amount The amount of tokens to mint */ function receiveMessage(address _user, uint256 _amount) external override onlyLinkedAdapter { - if (isMigrated) revert IOpUSDCBridgeAdapter_Migrated(); + if (messengerStatus == Status.Deprecated) revert IOpUSDCBridgeAdapter_Migrated(); // Mint the tokens to the user try IUSDC(USDC).mint(_user, _amount) { emit MessageReceived(_user, _amount, MESSENGER); @@ -290,4 +263,21 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { emit USDCFunctionSent(_selector); } + + /*/////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + ///////////////////////////////////////////////////////////////*/ + function _sendMessage(address _from, address _to, uint256 _amount, uint32 _minGasLimit) internal { + IUSDC(USDC).safeTransferFrom(_from, address(this), _amount); + + // Burn the tokens + IUSDC(USDC).burn(_amount); + + // Send the message to the linked adapter + ICrossDomainMessenger(MESSENGER).sendMessage( + LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit + ); + + emit MessageSent(_from, _to, _amount, MESSENGER, _minGasLimit); + } } diff --git a/src/contracts/universal/OpUSDCBridgeAdapter.sol b/src/contracts/universal/OpUSDCBridgeAdapter.sol index 7c10fc77..ba315be5 100644 --- a/src/contracts/universal/OpUSDCBridgeAdapter.sol +++ b/src/contracts/universal/OpUSDCBridgeAdapter.sol @@ -19,6 +19,9 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { /// @inheritdoc IOpUSDCBridgeAdapter address public immutable MESSENGER; + /// @inheritdoc IOpUSDCBridgeAdapter + Status public messengerStatus; + /// @inheritdoc IOpUSDCBridgeAdapter mapping(address _user => mapping(uint256 _nonce => bool _used)) public userNonces; diff --git a/src/interfaces/IL1OpUSDCBridgeAdapter.sol b/src/interfaces/IL1OpUSDCBridgeAdapter.sol index f8ef6448..5027cd20 100644 --- a/src/interfaces/IL1OpUSDCBridgeAdapter.sol +++ b/src/interfaces/IL1OpUSDCBridgeAdapter.sol @@ -2,24 +2,6 @@ pragma solidity 0.8.25; interface IL1OpUSDCBridgeAdapter { - /*/////////////////////////////////////////////////////////////// - ENUMS - ///////////////////////////////////////////////////////////////*/ - - /** - * @notice The status of an L1 Messenger - * @param Active The messenger is active - * @param Paused The messenger is paused - * @param Upgrading The messenger is upgrading - * @param Deprecated The messenger is deprecated - */ - enum Status { - Active, - Paused, - Upgrading, - Deprecated - } - /*/////////////////////////////////////////////////////////////// EVENTS ///////////////////////////////////////////////////////////////*/ @@ -98,10 +80,4 @@ interface IL1OpUSDCBridgeAdapter { * @return _burnCaller The address of the burn caller */ function burnCaller() external view returns (address _burnCaller); - - /** - * @notice Fetches the status of the messenger - * @return _status The status of the messenger - */ - function messengerStatus() external view returns (Status _status); } diff --git a/src/interfaces/IL2OpUSDCBridgeAdapter.sol b/src/interfaces/IL2OpUSDCBridgeAdapter.sol index 86a1da5d..77e65c1f 100644 --- a/src/interfaces/IL2OpUSDCBridgeAdapter.sol +++ b/src/interfaces/IL2OpUSDCBridgeAdapter.sol @@ -55,17 +55,6 @@ interface IL2OpUSDCBridgeAdapter { /*/////////////////////////////////////////////////////////////// VARIABLES ///////////////////////////////////////////////////////////////*/ - /** - * @notice Fetches whether messaging is disabled - * @return _isMessagingDisabled Whether messaging is disabled - */ - function isMessagingDisabled() external view returns (bool _isMessagingDisabled); - - /** - * @notice Fetches whether bridged USDC has been migrated to native USDC - * @return _isMigrated Whether bridged USDC has been migrated to native USDC - */ - function isMigrated() external view returns (bool _isMigrated); /** * @notice Fetches the address of the role caller diff --git a/src/interfaces/IOpUSDCBridgeAdapter.sol b/src/interfaces/IOpUSDCBridgeAdapter.sol index c99e6873..c7ca1d8d 100644 --- a/src/interfaces/IOpUSDCBridgeAdapter.sol +++ b/src/interfaces/IOpUSDCBridgeAdapter.sol @@ -2,6 +2,23 @@ pragma solidity 0.8.25; interface IOpUSDCBridgeAdapter { + /*/////////////////////////////////////////////////////////////// + ENUMS + ///////////////////////////////////////////////////////////////*/ + + /** + * @notice The status of an L1 Messenger + * @param Active The messenger is active + * @param Paused The messenger is paused + * @param Upgrading The messenger is upgrading + * @param Deprecated The messenger is deprecated + */ + enum Status { + Active, + Paused, + Upgrading, + Deprecated + } /*/////////////////////////////////////////////////////////////// EVENTS ///////////////////////////////////////////////////////////////*/ @@ -208,6 +225,12 @@ interface IOpUSDCBridgeAdapter { // solhint-disable-next-line func-name-mixedcase function MESSENGER() external view returns (address _messenger); + /** + * @notice Fetches the status of the messenger + * @return _status The status of the messenger + */ + function messengerStatus() external view returns (Status _status); + /** * @notice Returns the nonce of a given user to avoid replay attacks * @param _user The user to check for diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index f48e25ee..3294a8d0 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -204,7 +204,7 @@ contract Integration_Migration is IntegrationBase { vm.prank(_owner); l1Adapter.migrateToNative(_circle, _circle, _minGasLimitReceiveOnL2, _minGasLimitSetBurnAmount); - assertEq(uint256(l1Adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Upgrading)); + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Upgrading)); assertEq(l1Adapter.burnCaller(), _circle); vm.selectFork(optimism); @@ -219,8 +219,7 @@ contract Integration_Migration is IntegrationBase { uint256 _burnAmount = bridgedUSDC.totalSupply(); - assert(l2Adapter.isMigrated()); - assert(l2Adapter.isMessagingDisabled()); + assertEq(uint256(l2Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Deprecated)); assertEq(l2Adapter.roleCaller(), _circle); assertEq(bridgedUSDC.isMinter(address(l2Adapter)), false); @@ -240,7 +239,7 @@ contract Integration_Migration is IntegrationBase { assertEq(l1Adapter.burnAmount(), _burnAmount); assertEq(l1Adapter.USDC(), address(MAINNET_USDC)); - assertEq(uint256(l1Adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Deprecated)); + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Deprecated)); vm.prank(_circle); l1Adapter.burnLockedUSDC(); @@ -259,12 +258,12 @@ contract Integration_Integration_PermissionedFlows is IntegrationBase { function test_stopAndResumeMessaging() public { vm.selectFork(mainnet); - assertEq(uint256(l1Adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Active)); + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Active)); vm.prank(_owner); l1Adapter.stopMessaging(_MIN_GAS_LIMIT); - assertEq(uint256(l1Adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Paused)); + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Paused)); vm.selectFork(optimism); _relayL1ToL2Message( @@ -276,14 +275,14 @@ contract Integration_Integration_PermissionedFlows is IntegrationBase { abi.encodeWithSignature('receiveStopMessaging()') ); - assert(l2Adapter.isMessagingDisabled()); + assertEq(uint256(l2Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Paused)); vm.selectFork(mainnet); vm.prank(_owner); l1Adapter.resumeMessaging(_MIN_GAS_LIMIT); - assertEq(uint256(l1Adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Active)); + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Active)); vm.selectFork(optimism); @@ -296,7 +295,7 @@ contract Integration_Integration_PermissionedFlows is IntegrationBase { abi.encodeWithSignature('receiveResumeMessaging()') ); - assertEq(l2Adapter.isMessagingDisabled(), false); + assertEq(uint256(l2Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Active)); } /** diff --git a/test/unit/L1OpUSDCBridgeAdapter.t.sol b/test/unit/L1OpUSDCBridgeAdapter.t.sol index b818b3f8..6e407aef 100644 --- a/test/unit/L1OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L1OpUSDCBridgeAdapter.t.sol @@ -138,7 +138,7 @@ contract L1OpUSDCBridgeAdapter_Unit_MigrateToNative is Base { ) external { vm.assume(_roleCaller != address(0)); vm.assume(_burnCaller != address(0)); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Paused); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); // Execute vm.prank(_owner); @@ -174,7 +174,7 @@ contract L1OpUSDCBridgeAdapter_Unit_MigrateToNative is Base { assertEq(adapter.burnCaller(), _burnCaller, 'Circle should be set to the new owner'); assertEq( uint256(adapter.messengerStatus()), - uint256(IL1OpUSDCBridgeAdapter.Status.Upgrading), + uint256(IOpUSDCBridgeAdapter.Status.Upgrading), 'Is upgrading should be set to true' ); } @@ -218,7 +218,7 @@ contract L1OpUSDCBridgeAdapter_Unit_MigrateToNative is Base { vm.assume(_roleCaller != address(0)); vm.assume(_burnCaller != address(0)); adapter.forTest_setBurnCaller(_roleCaller); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Upgrading); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Upgrading); _mockAndExpect( _messenger, @@ -299,10 +299,10 @@ contract L1OpUSDCBridgeAdapter_Unit_SetBurnAmount is Base { * @notice Check the functions reverts when messenger status is not upgrading */ function test_revertIfMessengerStatusIsNotUpgrading(uint256 _amount, uint256 _status) external { - _status = bound(_status, 0, uint256(type(IL1OpUSDCBridgeAdapter.Status).max) - 1); - vm.assume(_status != uint256(IL1OpUSDCBridgeAdapter.Status.Upgrading)); + _status = bound(_status, 0, uint256(type(IOpUSDCBridgeAdapter.Status).max) - 1); + vm.assume(_status != uint256(IOpUSDCBridgeAdapter.Status.Upgrading)); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status(_status)); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status(_status)); vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); @@ -318,7 +318,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SetBurnAmount is Base { function test_setAmount(uint256 _burnAmount) external { vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Upgrading); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Upgrading); // Execute vm.prank(_messenger); @@ -334,7 +334,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SetBurnAmount is Base { function test_setStatus(uint256 _burnAmount) external { vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Upgrading); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Upgrading); // Execute vm.prank(_messenger); @@ -343,7 +343,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SetBurnAmount is Base { // Assert assertEq( uint256(adapter.messengerStatus()), - uint256(IL1OpUSDCBridgeAdapter.Status.Deprecated), + uint256(IOpUSDCBridgeAdapter.Status.Deprecated), 'Messenger status should be set to Deprecated' ); } @@ -354,7 +354,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SetBurnAmount is Base { function test_emitEvent(uint256 _burnAmount) external { vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Upgrading); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Upgrading); // Execute vm.prank(_messenger); @@ -389,7 +389,7 @@ contract L1OpUSDCBridgeAdapter_Unit_BurnLockedUSDC is Base { */ function test_burnNotCalledIfAmountIsZero(address _circle) external { adapter.forTest_setBurnCaller(_circle); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Deprecated); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); adapter.forTest_setBurnAmount(0); // Execute @@ -402,7 +402,7 @@ contract L1OpUSDCBridgeAdapter_Unit_BurnLockedUSDC is Base { */ function test_expectedCall(uint256 _burnAmount, address _circle) external { adapter.forTest_setBurnCaller(_circle); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Deprecated); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); vm.assume(_burnAmount > 0); @@ -422,7 +422,7 @@ contract L1OpUSDCBridgeAdapter_Unit_BurnLockedUSDC is Base { function test_resetStorageValues(uint256 _burnAmount, address _circle) external { vm.assume(_burnAmount > 0); adapter.forTest_setBurnCaller(_circle); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Deprecated); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); vm.mockCall( _usdc, abi.encodeWithSignature('burn(address,uint256)', address(adapter), _burnAmount), abi.encode(true) @@ -446,7 +446,7 @@ contract L1OpUSDCBridgeAdapter_Unit_BurnLockedUSDC is Base { vm.assume(_burnAmount > 0); vm.assume(_burnAmount > _balanceOf); adapter.forTest_setBurnCaller(_circle); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Deprecated); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); // solhint-disable-next-line max-line-length vm.mockCall(_usdc, abi.encodeWithSignature('burn(address,uint256)', address(adapter), _balanceOf), abi.encode(true)); @@ -467,7 +467,7 @@ contract L1OpUSDCBridgeAdapter_Unit_BurnLockedUSDC is Base { */ function test_emitEvent(uint256 _burnAmount, address _circle) external { adapter.forTest_setBurnCaller(_circle); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Deprecated); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); vm.mockCall(_usdc, abi.encodeWithSignature('burn(address)', address(adapter)), abi.encode(true)); vm.mockCall(_usdc, abi.encodeWithSignature('balanceOf(address)', address(adapter)), abi.encode(_burnAmount)); @@ -505,7 +505,7 @@ contract L1OpUSDCBridgeAdapter_Unit_StopMessaging is Base { * @notice Check that the function reverts if messaging is in an unexpected state */ function test_revertIfMessagingIsWrongState(uint32 _minGasLimit) public { - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Deprecated); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); // Execute vm.prank(_owner); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_MessagingDisabled.selector); @@ -528,7 +528,7 @@ contract L1OpUSDCBridgeAdapter_Unit_StopMessaging is Base { vm.prank(_owner); adapter.stopMessaging(_minGasLimit); assertEq( - uint256(adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Paused), 'Messenger should be paused' + uint256(adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Paused), 'Messenger should be paused' ); } @@ -536,7 +536,7 @@ contract L1OpUSDCBridgeAdapter_Unit_StopMessaging is Base { * @notice Check that messenger status gets set to paused */ function test_setMessengerStatusCanBeCalledIfPaused(uint32 _minGasLimit) public { - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Paused); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); bytes memory _messageData = abi.encodeWithSignature('receiveStopMessaging()'); _mockAndExpect( @@ -549,7 +549,7 @@ contract L1OpUSDCBridgeAdapter_Unit_StopMessaging is Base { vm.prank(_owner); adapter.stopMessaging(_minGasLimit); assertEq( - uint256(adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Paused), 'Messenger should be paused' + uint256(adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Paused), 'Messenger should be paused' ); } @@ -594,7 +594,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ResumeMessaging is Base { * @notice Check that it reverts if bridging is not paused or active */ function test_RevertIfBridgingIsNotPausedOrActive(uint32 _minGasLimit) external { - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Deprecated); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); // Execute vm.prank(_owner); @@ -606,7 +606,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ResumeMessaging is Base { * @notice Check that the messenger status is set to active */ function test_setMessengerStatusToActive(uint32 _minGasLimit) external { - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Paused); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); _mockAndExpect( _messenger, abi.encodeWithSignature( @@ -623,7 +623,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ResumeMessaging is Base { adapter.resumeMessaging(_minGasLimit); assertEq( - uint256(adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Active), 'Messenger should be active' + uint256(adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Active), 'Messenger should be active' ); } @@ -631,7 +631,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ResumeMessaging is Base { * @notice Check that resume can still be called when in an active state */ function test_resumeCanBeCalledIfActive(uint32 _minGasLimit) external { - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Active); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Active); _mockAndExpect( _messenger, abi.encodeWithSignature( @@ -648,7 +648,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ResumeMessaging is Base { adapter.resumeMessaging(_minGasLimit); assertEq( - uint256(adapter.messengerStatus()), uint256(IL1OpUSDCBridgeAdapter.Status.Active), 'Messenger should be active' + uint256(adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Active), 'Messenger should be active' ); } @@ -656,7 +656,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ResumeMessaging is Base { * @notice Check that the event is emitted as expected */ function test_emitEvent(uint32 _minGasLimit) external { - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Paused); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); // Mock calls vm.mockCall( _messenger, @@ -701,7 +701,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SendMessage is Base { function test_revertOnMessengerNotActive(address _to, uint256 _amount, uint32 _minGasLimit) external { vm.mockCall(_usdc, abi.encodeWithSignature('isBlacklisted(address)', _to), abi.encode(false)); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Paused); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); // Execute vm.prank(_user); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_MessagingDisabled.selector); @@ -798,7 +798,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SendMessageWithSignature is Base { uint32 _minGasLimit ) external { vm.mockCall(_usdc, abi.encodeWithSignature('isBlacklisted(address)', _to), abi.encode(false)); - adapter.forTest_setMessengerStatus(IL1OpUSDCBridgeAdapter.Status.Paused); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); // Execute vm.prank(_user); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_MessagingDisabled.selector); diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index 8baf93f6..961f790c 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -16,18 +16,14 @@ contract ForTestL2OpUSDCBridgeAdapter is L2OpUSDCBridgeAdapter { address _owner ) L2OpUSDCBridgeAdapter(_usdc, _messenger, _linkedAdapter, _owner) {} - function forTest_setIsMessagingDisabled() external { - isMessagingDisabled = true; + function forTest_setMessengerStatus(Status _status) external { + messengerStatus = _status; } function forTest_setRoleCaller(address _roleCaller) external { roleCaller = _roleCaller; } - function forTest_setIsMigrated(bool _isMigrated) external { - isMigrated = _isMigrated; - } - function forTest_setUserNonce(address _user, uint256 _nonce, bool _used) external { userNonces[_user][_nonce] = _used; } @@ -146,7 +142,11 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMigrateToNative is Base { // Execute vm.prank(_messenger); adapter.receiveMigrateToNative(_roleCaller, _setBurnAmountMinGasLimit); - assertEq(adapter.isMessagingDisabled(), true, 'Messaging should be disabled'); + assertEq( + uint256(adapter.messengerStatus()), + uint256(IOpUSDCBridgeAdapter.Status.Deprecated), + 'Messaging should be disabled' + ); assertEq(adapter.roleCaller(), _roleCaller, 'Role caller should be set to the new owner'); } @@ -226,7 +226,11 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveStopMessaging is Base { vm.prank(_notMessenger); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_InvalidSender.selector); adapter.receiveStopMessaging(); - assertEq(adapter.isMessagingDisabled(), false, 'Messaging should not be disabled'); + assertEq( + uint256(adapter.messengerStatus()), + uint256(IOpUSDCBridgeAdapter.Status.Active), + 'Messaging should not be disabled' + ); } /** @@ -241,7 +245,11 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveStopMessaging is Base { vm.prank(_messenger); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_InvalidSender.selector); adapter.receiveStopMessaging(); - assertEq(adapter.isMessagingDisabled(), false, 'Messaging should not be disabled'); + assertEq( + uint256(adapter.messengerStatus()), + uint256(IOpUSDCBridgeAdapter.Status.Active), + 'Messaging should not be disabled' + ); } /** @@ -253,7 +261,9 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveStopMessaging is Base { // Execute vm.prank(_messenger); adapter.receiveStopMessaging(); - assertEq(adapter.isMessagingDisabled(), true, 'Messaging should be disabled'); + assertEq( + uint256(adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Paused), 'Messaging should be disabled' + ); } /** @@ -303,15 +313,17 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveResumeMessaging is Base { } /** - * @notice Check that isMessagingDisabled is set to false + * @notice Check that messaging is enabled */ - function test_setIsMessagingDisabledToFalse() external { + function test_setMessengerStatusToActive() external { _mockAndExpect(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); // Execute vm.prank(_messenger); adapter.receiveResumeMessaging(); - assertEq(adapter.isMessagingDisabled(), false, 'Messaging should be disabled'); + assertEq( + uint256(adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Active), 'Messaging should be enabled' + ); } /** @@ -350,8 +362,8 @@ contract L2OpUSDCBridgeAdapter_Unit_SendMessage is Base { /** * @notice Check that sending a message reverts if messaging is disabled */ - function test_revertOnMessagingDisabled(address _to, uint256 _amount, uint32 _minGasLimit) external { - adapter.forTest_setIsMessagingDisabled(); + function test_revertOnMessagingPaused(address _to, uint256 _amount, uint32 _minGasLimit) external { + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); vm.mockCall(_usdc, abi.encodeWithSignature('isBlacklisted(address)', _to), abi.encode(false)); // Execute vm.prank(_user); @@ -464,7 +476,7 @@ contract L2OpUSDCBridgeAdapter_Unit_SendMessageWithSignature is Base { uint256 _deadline, uint32 _minGasLimit ) external { - adapter.forTest_setIsMessagingDisabled(); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Paused); vm.mockCall(_usdc, abi.encodeWithSignature('isBlacklisted(address)', _to), abi.encode(false)); @@ -630,7 +642,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { * @notice Check that the function reverts if the contract is migrated to native */ function test_revertIfMigratedToNative(uint256 _amount) external { - adapter.forTest_setIsMigrated(true); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); // Mock calls vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); // Execute From 2b9a6327503debc109774364dedb2b61847ca46f Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 12:29:01 -0300 Subject: [PATCH 09/23] refactor: use internal function to send messages --- src/contracts/L1OpUSDCBridgeAdapter.sol | 35 ++++++++++++------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index d25f7fe0..4a379fc4 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -200,15 +200,7 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Ensure messaging is enabled if (messengerStatus != Status.Active) revert IOpUSDCBridgeAdapter_MessagingDisabled(); - // Transfer the tokens to the contract - IUSDC(USDC).safeTransferFrom(msg.sender, address(this), _amount); - - // Send the message to the linked adapter - ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit - ); - - emit MessageSent(msg.sender, _to, _amount, MESSENGER, _minGasLimit); + _sendMessage(msg.sender, _to, _amount, _minGasLimit); } /** @@ -251,15 +243,7 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Mark the nonce as used userNonces[_signer][_nonce] = true; - // Transfer the tokens to the contract - IUSDC(USDC).safeTransferFrom(_signer, address(this), _amount); - - // Send the message to the linked adapter - ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit - ); - - emit MessageSent(_signer, _to, _amount, MESSENGER, _minGasLimit); + _sendMessage(_signer, _to, _amount, _minGasLimit); } /** @@ -304,4 +288,19 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { if (msg.sender != address(this)) revert IOpUSDCBridgeAdapter_InvalidSender(); IUSDC(USDC).safeTransfer(_to, _amount); } + + /*/////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + ///////////////////////////////////////////////////////////////*/ + function _sendMessage(address _from, address _to, uint256 _amount, uint32 _minGasLimit) internal { + // Transfer the tokens to the contract + IUSDC(USDC).safeTransferFrom(_from, address(this), _amount); + + // Send the message to the linked adapter + ICrossDomainMessenger(MESSENGER).sendMessage( + LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit + ); + + emit MessageSent(_from, _to, _amount, MESSENGER, _minGasLimit); + } } From e0596e544a64ea7d463072f76022c00d53ca5a91 Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 13:43:43 -0300 Subject: [PATCH 10/23] refactor: add spender param to messages --- src/contracts/L1OpUSDCBridgeAdapter.sol | 5 ++- src/contracts/L2OpUSDCBridgeAdapter.sol | 13 +++++-- .../universal/OpUSDCBridgeAdapter.sol | 3 +- src/interfaces/IOpUSDCBridgeAdapter.sol | 3 +- test/integration/IntegrationBase.sol | 2 +- test/integration/L1OpUSDCBridgeAdapter.t.sol | 8 ++-- test/integration/L2OpUSDCBridgeAdapter.t.sol | 8 ++-- test/unit/L1OpUSDCBridgeAdapter.t.sol | 22 +++++------ test/unit/L2OpUSDCBridgeAdapter.t.sol | 38 +++++++++---------- test/unit/OpUSDCBridgeAdapter.t.sol | 4 +- 10 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index 4a379fc4..d73a1680 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -250,9 +250,10 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @notice Receive the message from the other chain and transfer the tokens to the user * @dev This function should only be called when receiving a message to transfer the tokens * @param _user The user to transfer the tokens to + * @param _spender The address that provided the tokens * @param _amount The amount of tokens to transfer */ - function receiveMessage(address _user, uint256 _amount) external override onlyLinkedAdapter { + function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter { // Transfer the tokens to the user try this.attemptTransfer(_user, _amount) { emit MessageReceived(_user, _amount, MESSENGER); @@ -298,7 +299,7 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Send the message to the linked adapter ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit + LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _from, _amount)), _minGasLimit ); emit MessageSent(_from, _to, _amount, MESSENGER, _minGasLimit); diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 253c92aa..f92126f8 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -199,10 +199,17 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @notice Receive the message from the other chain and mint the bridged representation for the user * @dev This function should only be called when receiving a message to mint the bridged representation * @param _user The user to mint the bridged representation for + * @param _spender The address that provided the tokens * @param _amount The amount of tokens to mint */ - function receiveMessage(address _user, uint256 _amount) external override onlyLinkedAdapter { - if (messengerStatus == Status.Deprecated) revert IOpUSDCBridgeAdapter_Migrated(); + function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter { + if (messengerStatus == Status.Deprecated) { + //Return the funds to the user if the contract is deprecated + // The user will need to relay the message manually with a higher gas limit + ICrossDomainMessenger(MESSENGER).sendMessage( + LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), 0 + ); + } // Mint the tokens to the user try IUSDC(USDC).mint(_user, _amount) { emit MessageReceived(_user, _amount, MESSENGER); @@ -275,7 +282,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Send the message to the linked adapter ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _amount)), _minGasLimit + LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _from, _amount)), _minGasLimit ); emit MessageSent(_from, _to, _amount, MESSENGER, _minGasLimit); diff --git a/src/contracts/universal/OpUSDCBridgeAdapter.sol b/src/contracts/universal/OpUSDCBridgeAdapter.sol index ba315be5..73a9ddcf 100644 --- a/src/contracts/universal/OpUSDCBridgeAdapter.sol +++ b/src/contracts/universal/OpUSDCBridgeAdapter.sol @@ -78,9 +78,10 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { * @notice Receive the message from the other chain and mint the bridged representation for the user * @dev This function should only be called when receiving a message to mint the bridged representation * @param _user The user to mint the bridged representation for + * @param _spender The address that provided the tokens * @param _amount The amount of tokens to mint */ - function receiveMessage(address _user, uint256 _amount) external virtual; + function receiveMessage(address _user, address _spender, uint256 _amount) external virtual; /** * @notice Withdraws the blacklisted funds from the contract if they get unblacklisted diff --git a/src/interfaces/IOpUSDCBridgeAdapter.sol b/src/interfaces/IOpUSDCBridgeAdapter.sol index c7ca1d8d..1928ef81 100644 --- a/src/interfaces/IOpUSDCBridgeAdapter.sol +++ b/src/interfaces/IOpUSDCBridgeAdapter.sol @@ -184,9 +184,10 @@ interface IOpUSDCBridgeAdapter { * @notice Receive the message from the other chain and mint the bridged representation for the user * @dev This function should only be called when receiving a message to mint the bridged representation * @param _user The user to mint the bridged representation for + * @param _spender The address that provided the tokens * @param _amount The amount of tokens to mint */ - function receiveMessage(address _user, uint256 _amount) external; + function receiveMessage(address _user, address _spender, uint256 _amount) external; /** * @notice Withdraws the blacklisted funds from the contract if they get unblacklisted diff --git a/test/integration/IntegrationBase.sol b/test/integration/IntegrationBase.sol index 60af4bca..f2d0c285 100644 --- a/test/integration/IntegrationBase.sol +++ b/test/integration/IntegrationBase.sol @@ -176,7 +176,7 @@ contract IntegrationBase is Helpers { address(l2Adapter), _ZERO_VALUE, _minGasLimitMint, - abi.encodeWithSignature('receiveMessage(address,uint256)', _user, _supply) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _supply) ); } diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index 3294a8d0..14c359ab 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -33,7 +33,7 @@ contract Integration_Bridging is IntegrationBase { address(l2Adapter), _ZERO_VALUE, 1_000_000, - abi.encodeWithSignature('receiveMessage(address,uint256)', _user, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount) ); assertEq(bridgedUSDC.balanceOf(_user), _userBalanceBefore + _amount); @@ -67,7 +67,7 @@ contract Integration_Bridging is IntegrationBase { address(l2Adapter), _ZERO_VALUE, 1_000_000, - abi.encodeWithSignature('receiveMessage(address,uint256)', _l2Target, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _l2Target, _user, _amount) ); assertEq(bridgedUSDC.balanceOf(_l2Target), _userBalanceBefore + _amount); @@ -112,7 +112,7 @@ contract Integration_Bridging is IntegrationBase { address(l2Adapter), _ZERO_VALUE, 1_000_000, - abi.encodeWithSignature('receiveMessage(address,uint256)', _signerAd, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _signerAd, _signerAd, _amount) ); assertEq(bridgedUSDC.balanceOf(_signerAd), _userBalanceBefore + _amount); @@ -321,7 +321,7 @@ contract Integration_Integration_PermissionedFlows is IntegrationBase { address(l1Adapter), _ZERO_VALUE, _MIN_GAS_LIMIT, - abi.encodeWithSignature('receiveMessage(address,uint256)', _user, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount) ); assertEq(MAINNET_USDC.balanceOf(_user), 0); diff --git a/test/integration/L2OpUSDCBridgeAdapter.t.sol b/test/integration/L2OpUSDCBridgeAdapter.t.sol index 22538a18..ba7a64bb 100644 --- a/test/integration/L2OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L2OpUSDCBridgeAdapter.t.sol @@ -46,7 +46,7 @@ contract Integration_Bridging is IntegrationBase { address(l1Adapter), _ZERO_VALUE, _MIN_GAS_LIMIT, - abi.encodeWithSignature('receiveMessage(address,uint256)', _user, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount) ); assertEq(MAINNET_USDC.balanceOf(_user), _userBalanceBefore + _amount); @@ -81,7 +81,7 @@ contract Integration_Bridging is IntegrationBase { address(l1Adapter), _ZERO_VALUE, _MIN_GAS_LIMIT, - abi.encodeWithSignature('receiveMessage(address,uint256)', _l1Target, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _l1Target, _user, _amount) ); assertEq(MAINNET_USDC.balanceOf(_l1Target), _userBalanceBefore + _amount); @@ -115,7 +115,7 @@ contract Integration_Bridging is IntegrationBase { address(l1Adapter), _ZERO_VALUE, _MIN_GAS_LIMIT, - abi.encodeWithSignature('receiveMessage(address,uint256)', _user, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount) ); assertEq(MAINNET_USDC.balanceOf(_user), 0); @@ -157,7 +157,7 @@ contract Integration_Bridging is IntegrationBase { address(l1Adapter), _ZERO_VALUE, _MIN_GAS_LIMIT, - abi.encodeWithSignature('receiveMessage(address,uint256)', _signerAd, _amount) + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _signerAd, _signerAd, _amount) ); assertEq(MAINNET_USDC.balanceOf(_signerAd), _userBalanceBefore + _amount); diff --git a/test/unit/L1OpUSDCBridgeAdapter.t.sol b/test/unit/L1OpUSDCBridgeAdapter.t.sol index 6e407aef..52b3dd71 100644 --- a/test/unit/L1OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L1OpUSDCBridgeAdapter.t.sol @@ -723,7 +723,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SendMessage is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _user, _amount), _minGasLimit ), abi.encode() @@ -751,7 +751,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SendMessage is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _amount), _minGasLimit ), abi.encode() @@ -897,7 +897,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SendMessageWithSignature is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _signerAd, _amount), _minGasLimit ), abi.encode() @@ -934,7 +934,7 @@ contract L1OpUSDCBridgeAdapter_Unit_SendMessageWithSignature is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _signerAd, _amount), _minGasLimit ), abi.encode() @@ -959,7 +959,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_user); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_InvalidSender.selector); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** @@ -973,7 +973,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_messenger); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_InvalidSender.selector); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** @@ -987,7 +987,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** @@ -1004,7 +1004,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { emit MessageReceived(_user, _amount, _messenger); vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** @@ -1020,7 +1020,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); assertEq(adapter.userBlacklistedFunds(_user), _amount, 'User blacklisted funds should be incremented'); } @@ -1039,7 +1039,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); assertEq(adapter.userBlacklistedFunds(_user), _amount, 'User blacklisted funds should be incremented'); } @@ -1060,7 +1060,7 @@ contract L1OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { vm.expectEmit(true, true, true, true); vm.prank(_messenger); emit MessageFailed(_user, _amount); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } } diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index 961f790c..a868c41f 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -407,7 +407,7 @@ contract L2OpUSDCBridgeAdapter_Unit_SendMessage is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _user, _amount), _minGasLimit ), abi.encode() @@ -430,7 +430,7 @@ contract L2OpUSDCBridgeAdapter_Unit_SendMessage is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _amount), _minGasLimit ), abi.encode() @@ -556,7 +556,7 @@ contract L2OpUSDCBridgeAdapter_Unit_SendMessageWithSignature is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _signerAd, _amount), _minGasLimit ), abi.encode() @@ -594,7 +594,7 @@ contract L2OpUSDCBridgeAdapter_Unit_SendMessageWithSignature is Base { abi.encodeWithSignature( 'sendMessage(address,bytes,uint32)', _linkedAdapter, - abi.encodeWithSignature('receiveMessage(address,uint256)', _to, _amount), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _to, _amount), _minGasLimit ), abi.encode() @@ -620,7 +620,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_user); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_InvalidSender.selector); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** @@ -635,21 +635,21 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_messenger); vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_InvalidSender.selector); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** * @notice Check that the function reverts if the contract is migrated to native */ - function test_revertIfMigratedToNative(uint256 _amount) external { - adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); - // Mock calls - vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); - // Execute - vm.prank(_messenger); - vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); - adapter.receiveMessage(_user, _amount); - } + // function test_revertIfMigratedToNative(uint256 _amount) external { + // adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); + // // Mock calls + // vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); + // // Execute + // vm.prank(_messenger); + // vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); + // adapter.receiveMessage(_user, _user, _amount); + // } /** * @notice Check that the token minting works as expected @@ -662,7 +662,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { // Execute vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** @@ -679,7 +679,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { emit MessageReceived(_user, _amount, _messenger); vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } /** @@ -695,7 +695,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { vm.mockCallRevert(_usdc, abi.encodeWithSignature('mint(address,uint256)', _user, _amount), abi.encode(false)); // Execute vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); assertEq(adapter.userBlacklistedFunds(_user), _amount, 'Blacklisted funds should be set to the amount'); } @@ -718,7 +718,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { emit MessageFailed(_user, _amount); vm.prank(_messenger); - adapter.receiveMessage(_user, _amount); + adapter.receiveMessage(_user, _user, _amount); } } diff --git a/test/unit/OpUSDCBridgeAdapter.t.sol b/test/unit/OpUSDCBridgeAdapter.t.sol index 2b3d8f33..f6ea1720 100644 --- a/test/unit/OpUSDCBridgeAdapter.t.sol +++ b/test/unit/OpUSDCBridgeAdapter.t.sol @@ -14,7 +14,7 @@ contract ForTestOpUSDCBridgeAdapter is OpUSDCBridgeAdapter { address _owner ) OpUSDCBridgeAdapter(_usdc, _messenger, _linkedAdapter, _owner) {} - function receiveMessage(address _user, uint256 _amount) external override {} + function receiveMessage(address _user, address _spender, uint256 _amount) external override {} function sendMessage(address _to, uint256 _amount, uint32 _minGasLimit) external override {} @@ -90,7 +90,7 @@ contract ForTestOpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { */ function test_doNothing() public { // Execute - adapter.receiveMessage(address(0), 0); + adapter.receiveMessage(address(0), address(0), 0); } } From 4a75bc6e64e2a469feddfe69f9a0d5da80386ece Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 14:31:50 -0300 Subject: [PATCH 11/23] refactor: add sanity check --- src/contracts/L1OpUSDCBridgeAdapter.sol | 3 +-- src/contracts/L2OpUSDCBridgeAdapter.sol | 5 ++++- test/integration/L1OpUSDCBridgeAdapter.t.sol | 1 - test/unit/L1OpUSDCBridgeAdapter.t.sol | 2 +- test/unit/L2OpUSDCBridgeAdapter.t.sol | 18 +++++++++--------- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index d73a1680..f3bffc03 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -250,10 +250,9 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @notice Receive the message from the other chain and transfer the tokens to the user * @dev This function should only be called when receiving a message to transfer the tokens * @param _user The user to transfer the tokens to - * @param _spender The address that provided the tokens * @param _amount The amount of tokens to transfer */ - function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter { + function receiveMessage(address _user, address, uint256 _amount) external override onlyLinkedAdapter { // Transfer the tokens to the user try this.attemptTransfer(_user, _amount) { emit MessageReceived(_user, _amount, MESSENGER); diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index f92126f8..88e99700 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -117,6 +117,8 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @notice Receive the stop messaging message from the linked adapter and stop outgoing messages */ function receiveStopMessaging() external onlyLinkedAdapter { + if (messengerStatus == Status.Deprecated) revert IOpUSDCBridgeAdapter_MessagingDisabled(); + messengerStatus = Status.Paused; emit MessagingStopped(MESSENGER); @@ -126,7 +128,8 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @notice Resume messaging after it was stopped */ function receiveResumeMessaging() external onlyLinkedAdapter { - // NOTE: This is safe because this message can only be received when messaging is not deprecated on the L1 messenger + if (messengerStatus == Status.Deprecated) revert IOpUSDCBridgeAdapter_MessagingDisabled(); + messengerStatus = Status.Active; emit MessagingResumed(MESSENGER); diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index 14c359ab..1a07f5c8 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.25; import {IntegrationBase} from './IntegrationBase.sol'; -import {IL1OpUSDCBridgeAdapter} from 'interfaces/IL1OpUSDCBridgeAdapter.sol'; import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; contract Integration_Bridging is IntegrationBase { diff --git a/test/unit/L1OpUSDCBridgeAdapter.t.sol b/test/unit/L1OpUSDCBridgeAdapter.t.sol index 52b3dd71..c21c5884 100644 --- a/test/unit/L1OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L1OpUSDCBridgeAdapter.t.sol @@ -1,7 +1,7 @@ pragma solidity ^0.8.25; import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {IL1OpUSDCBridgeAdapter, L1OpUSDCBridgeAdapter} from 'contracts/L1OpUSDCBridgeAdapter.sol'; +import {L1OpUSDCBridgeAdapter} from 'contracts/L1OpUSDCBridgeAdapter.sol'; import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; import {Helpers} from 'test/utils/Helpers.sol'; diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index a868c41f..a1b49a30 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -641,15 +641,15 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { /** * @notice Check that the function reverts if the contract is migrated to native */ - // function test_revertIfMigratedToNative(uint256 _amount) external { - // adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); - // // Mock calls - // vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); - // // Execute - // vm.prank(_messenger); - // vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); - // adapter.receiveMessage(_user, _user, _amount); - // } + function test_revertIfMigratedToNative(uint256 _amount) external { + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); + // Mock calls + vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); + // Execute + vm.prank(_messenger); + vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); + adapter.receiveMessage(_user, _user, _amount); + } /** * @notice Check that the token minting works as expected From e1e7eae35007de2c0b960bec40e9ed2ba68a8700 Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 14:49:42 -0300 Subject: [PATCH 12/23] refactor: receive message logic --- src/contracts/L2OpUSDCBridgeAdapter.sol | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 88e99700..f9c888e6 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -207,18 +207,18 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { */ function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter { if (messengerStatus == Status.Deprecated) { - //Return the funds to the user if the contract is deprecated - // The user will need to relay the message manually with a higher gas limit + // Return the funds to the address where the tokens were sent from ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), 0 + LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), 150_000 ); - } - // Mint the tokens to the user - try IUSDC(USDC).mint(_user, _amount) { - emit MessageReceived(_user, _amount, MESSENGER); - } catch { - userBlacklistedFunds[_user] += _amount; - emit MessageFailed(_user, _amount); + } else { + // Mint the tokens to the user + try IUSDC(USDC).mint(_user, _amount) { + emit MessageReceived(_user, _amount, MESSENGER); + } catch { + userBlacklistedFunds[_user] += _amount; + emit MessageFailed(_user, _amount); + } } } From aa81beb0427d72deadca55be82b56b9896c413df Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 19:35:44 -0300 Subject: [PATCH 13/23] test: add tests --- src/contracts/L1OpUSDCBridgeAdapter.sol | 26 ++++---- test/integration/L1OpUSDCBridgeAdapter.t.sol | 66 +++++++++++++++++++- test/unit/L1OpUSDCBridgeAdapter.t.sol | 20 ++++++ test/unit/L2OpUSDCBridgeAdapter.t.sol | 43 ++++++++++++- 4 files changed, 136 insertions(+), 19 deletions(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index f3bffc03..dbc41ef3 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -112,26 +112,22 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // If the adapter is not deprecated the burn amount has not been set if (messengerStatus != Status.Deprecated) revert IOpUSDCBridgeAdapter_BurnAmountNotSet(); - // Burn the USDC tokens - // NOTE: If in flight transactions fail due to user being blacklisted after migration - // The funds will just be trapped in this contract as its deprecated - // If the user is after unblacklisted, they will be able to withdraw their usdc + // NOTE: This is a very edge case and will only happen if the chain operator adds a second minter on L2 + // So now this adapter doesnt have the full backing supply locked in this contract + // Incase the bridged usdc token has other minters and the supply sent is greater then what we have + // We need to burn the full amount stored in this contract + // This could also cause in-flight messages to fail because of the multiple supply sources uint256 _burnAmount = burnAmount; - if (_burnAmount != 0) { - // NOTE: This is a very edge case and will only happen if the chain operator adds a second minter on L2 - // So now this adapter doesnt have the full backing supply locked in this contract - // Incase the bridged usdc token has other minters and the supply sent is greater then what we have - // We need to burn the full amount stored in this contract - // This could also cause in-flight messages to fail because of the multiple supply sources - uint256 _balanceOf = IUSDC(USDC).balanceOf(address(this)); - _burnAmount = _burnAmount > _balanceOf ? _balanceOf : _burnAmount; + uint256 _balanceOf = IUSDC(USDC).balanceOf(address(this)); + _burnAmount = _burnAmount > _balanceOf ? _balanceOf : _burnAmount; + // Burn the USDC tokens + if (_burnAmount != 0) { IUSDC(USDC).burn(_burnAmount); - - // Set the burn amount to 0 - burnAmount = 0; } + // Set the burn amount to 0 + burnAmount = 0; burnCaller = address(0); emit MigrationComplete(_burnAmount); } diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index 1a07f5c8..5778efb6 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -186,8 +186,6 @@ contract Integration_Migration is IntegrationBase { function setUp() public override { super.setUp(); - _mintSupplyOnL2(optimism, OP_ALIASED_L1_MESSENGER, _amount); - vm.selectFork(mainnet); // Adapter needs to be minter to burn vm.prank(MAINNET_USDC.masterMinter()); @@ -198,6 +196,70 @@ contract Integration_Migration is IntegrationBase { * @notice Test the migration to native usdc flow */ function test_migrationToNativeUSDC() public { + _mintSupplyOnL2(optimism, OP_ALIASED_L1_MESSENGER, _amount); + + vm.selectFork(mainnet); + + vm.prank(_owner); + l1Adapter.migrateToNative(_circle, _circle, _minGasLimitReceiveOnL2, _minGasLimitSetBurnAmount); + + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Upgrading)); + assertEq(l1Adapter.burnCaller(), _circle); + + vm.selectFork(optimism); + _relayL1ToL2Message( + OP_ALIASED_L1_MESSENGER, + address(l1Adapter), + address(l2Adapter), + _ZERO_VALUE, + _minGasLimitReceiveOnL2, + abi.encodeWithSignature('receiveMigrateToNative(address,uint32)', _circle, _minGasLimitSetBurnAmount) + ); + + uint256 _burnAmount = bridgedUSDC.totalSupply(); + + assertEq(uint256(l2Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Deprecated)); + assertEq(l2Adapter.roleCaller(), _circle); + assertEq(bridgedUSDC.isMinter(address(l2Adapter)), false); + + vm.prank(_circle); + l2Adapter.transferUSDCRoles(_circle); + + assertEq(bridgedUSDC.owner(), _circle); + + vm.selectFork(mainnet); + _relayL2ToL1Message( + address(l2Adapter), + address(l1Adapter), + _ZERO_VALUE, + _minGasLimitSetBurnAmount, + abi.encodeWithSignature('setBurnAmount(uint256)', _burnAmount) + ); + + assertEq(l1Adapter.burnAmount(), _burnAmount); + assertEq(l1Adapter.USDC(), address(MAINNET_USDC)); + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Deprecated)); + + vm.prank(_circle); + l1Adapter.burnLockedUSDC(); + + assertEq(MAINNET_USDC.balanceOf(address(l1Adapter)), 0); + assertEq(l1Adapter.burnAmount(), 0); + assertEq(l1Adapter.burnCaller(), address(0)); + } + + /** + * @notice Test the migration to native usdc flow with zero balance on L1 + * @dev This is a very edge case and will only happen if the chain operator adds a second minter on L2 + * So now this adapter doesnt have the full backing supply locked in this contract + */ + function test_migrationToNativeUSDCWithZeroBalanceOnL1() public { + vm.selectFork(optimism); + vm.prank(bridgedUSDC.masterMinter()); + bridgedUSDC.configureMinter(_owner, type(uint256).max); + vm.prank(_owner); + bridgedUSDC.mint(_owner, _amount); + vm.selectFork(mainnet); vm.prank(_owner); diff --git a/test/unit/L1OpUSDCBridgeAdapter.t.sol b/test/unit/L1OpUSDCBridgeAdapter.t.sol index c21c5884..62ea8c19 100644 --- a/test/unit/L1OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L1OpUSDCBridgeAdapter.t.sol @@ -391,6 +391,26 @@ contract L1OpUSDCBridgeAdapter_Unit_BurnLockedUSDC is Base { adapter.forTest_setBurnCaller(_circle); adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); adapter.forTest_setBurnAmount(0); + vm.mockCall(_usdc, abi.encodeWithSignature('balanceOf(address)', address(adapter)), abi.encode(uint256(0))); + // Execute + vm.prank(_circle); + adapter.burnLockedUSDC(); + } + + /** + * @notice Check that the burn function is called as expected when burn amount is greater than adapter balance + */ + function test_burnCalledIfAmountIsGteBalance(uint256 _burnAmount, uint256 _balance, address _circle) external { + adapter.forTest_setBurnCaller(_circle); + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); + + vm.assume(_balance > 0); + vm.assume(_burnAmount > _balance); + + _mockAndExpect(_usdc, abi.encodeWithSignature('burn(uint256)', _balance), abi.encode(true)); + _mockAndExpect(_usdc, abi.encodeWithSignature('balanceOf(address)', address(adapter)), abi.encode(_balance)); + + adapter.forTest_setBurnAmount(_burnAmount); // Execute vm.prank(_circle); diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index a1b49a30..dc660e86 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -252,6 +252,20 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveStopMessaging is Base { ); } + /** + * @notice Check that function reverts if status is Deprecated + */ + function test_revertIfDeprecated() external { + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); + + _mockAndExpect(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); + + // Execute + vm.prank(_messenger); + vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_MessagingDisabled.selector); + adapter.receiveStopMessaging(); + } + /** * @notice Check that isMessagingDisabled is set to true */ @@ -312,6 +326,20 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveResumeMessaging is Base { adapter.receiveResumeMessaging(); } + /** + * @notice Check that function reverts if status is Deprecated + */ + function test_revertIfDeprecated() external { + adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); + + _mockAndExpect(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); + + // Execute + vm.prank(_messenger); + vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_MessagingDisabled.selector); + adapter.receiveResumeMessaging(); + } + /** * @notice Check that messaging is enabled */ @@ -639,15 +667,26 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { } /** - * @notice Check that the function reverts if the contract is migrated to native + * @notice Check that the function returns the funds if the contract is deprecated */ function test_revertIfMigratedToNative(uint256 _amount) external { adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); // Mock calls vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); + + // Expected call + _mockAndExpect( + _messenger, + abi.encodeWithSignature( + 'sendMessage(address,bytes,uint32)', + _linkedAdapter, + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount), + 150_000 + ), + abi.encode() + ); // Execute vm.prank(_messenger); - vm.expectRevert(IOpUSDCBridgeAdapter.IOpUSDCBridgeAdapter_Migrated.selector); adapter.receiveMessage(_user, _user, _amount); } From 1fd4c61105f86bff672a36d0d5f432d6b459a465 Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 20:28:58 -0300 Subject: [PATCH 14/23] test: integration test after deprecation --- test/integration/L1OpUSDCBridgeAdapter.t.sol | 70 ++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index 5778efb6..72c54ab2 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -309,6 +309,76 @@ contract Integration_Migration is IntegrationBase { assertEq(l1Adapter.burnAmount(), 0); assertEq(l1Adapter.burnCaller(), address(0)); } + + /** + * @notice Test relay message after migration to native usdc + */ + function test_relayMessageAfterMigrationToNativeUSDC() public { + vm.selectFork(mainnet); + + uint256 _supply = 1_000_000; + + vm.startPrank(MAINNET_USDC.masterMinter()); + MAINNET_USDC.configureMinter(MAINNET_USDC.masterMinter(), _supply); + MAINNET_USDC.mint(_user, _supply); + vm.stopPrank(); + + vm.startPrank(_user); + MAINNET_USDC.approve(address(l1Adapter), _supply); + l1Adapter.sendMessage(_user, _supply, _MIN_GAS_LIMIT); + vm.stopPrank(); + + vm.prank(_owner); + l1Adapter.migrateToNative(_circle, _circle, _minGasLimitReceiveOnL2, _minGasLimitSetBurnAmount); + + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Upgrading)); + assertEq(l1Adapter.burnCaller(), _circle); + + vm.selectFork(optimism); + _relayL1ToL2Message( + OP_ALIASED_L1_MESSENGER, + address(l1Adapter), + address(l2Adapter), + _ZERO_VALUE, + _minGasLimitReceiveOnL2, + abi.encodeWithSignature('receiveMigrateToNative(address,uint32)', _circle, _minGasLimitSetBurnAmount) + ); + + uint256 _burnAmount = bridgedUSDC.totalSupply(); + assertEq(uint256(l2Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Deprecated)); + + vm.selectFork(mainnet); + _relayL2ToL1Message( + address(l2Adapter), + address(l1Adapter), + _ZERO_VALUE, + _minGasLimitSetBurnAmount, + abi.encodeWithSignature('setBurnAmount(uint256)', _burnAmount) + ); + + assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Deprecated)); + + vm.selectFork(optimism); + + vm.expectCall( + 0x4200000000000000000000000000000000000007, + abi.encodeWithSignature( + 'sendMessage(address,bytes,uint32)', + address(l1Adapter), + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount), + 150_000 + ) + ); + + _relayL1ToL2Message( + OP_ALIASED_L1_MESSENGER, + address(l1Adapter), + address(l2Adapter), + _ZERO_VALUE, + 1_000_000, + abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount) + ); + } } contract Integration_Integration_PermissionedFlows is IntegrationBase { From fce01186a45995b1170f41e2685c681c3fcc30e0 Mon Sep 17 00:00:00 2001 From: hexshire Date: Wed, 24 Jul 2024 20:31:29 -0300 Subject: [PATCH 15/23] test: integration test after deprecation --- test/integration/L1OpUSDCBridgeAdapter.t.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/integration/L1OpUSDCBridgeAdapter.t.sol b/test/integration/L1OpUSDCBridgeAdapter.t.sol index 72c54ab2..6be89235 100644 --- a/test/integration/L1OpUSDCBridgeAdapter.t.sol +++ b/test/integration/L1OpUSDCBridgeAdapter.t.sol @@ -331,9 +331,6 @@ contract Integration_Migration is IntegrationBase { vm.prank(_owner); l1Adapter.migrateToNative(_circle, _circle, _minGasLimitReceiveOnL2, _minGasLimitSetBurnAmount); - assertEq(uint256(l1Adapter.messengerStatus()), uint256(IOpUSDCBridgeAdapter.Status.Upgrading)); - assertEq(l1Adapter.burnCaller(), _circle); - vm.selectFork(optimism); _relayL1ToL2Message( OP_ALIASED_L1_MESSENGER, @@ -370,6 +367,8 @@ contract Integration_Migration is IntegrationBase { ) ); + uint256 _totalSupplyBefore = bridgedUSDC.totalSupply(); + _relayL1ToL2Message( OP_ALIASED_L1_MESSENGER, address(l1Adapter), @@ -378,6 +377,8 @@ contract Integration_Migration is IntegrationBase { 1_000_000, abi.encodeWithSignature('receiveMessage(address,address,uint256)', _user, _user, _amount) ); + + assertEq(bridgedUSDC.totalSupply(), _totalSupplyBefore); } } From 4f06e80e81efefa8737fc0eab3c4acf6e685e110 Mon Sep 17 00:00:00 2001 From: hexshire Date: Thu, 25 Jul 2024 11:12:14 -0300 Subject: [PATCH 16/23] chore: fix comment --- src/contracts/L2OpUSDCBridgeAdapter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index d9a93caf..261820c9 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -209,7 +209,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { */ function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter { if (messengerStatus == Status.Deprecated) { - // Return the funds to the address where the tokens were sent from + // Return the funds to the spender incase the target on L2 is a contract that can´t handle the funds on L1 ICrossDomainMessenger(MESSENGER).sendMessage( LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), 150_000 ); From 3bb8d4b006cf508b549bd0ac4dce24de0c0cecbb Mon Sep 17 00:00:00 2001 From: excaliborr Date: Thu, 25 Jul 2024 10:27:30 -0400 Subject: [PATCH 17/23] fix: eip-712 compliance --- src/contracts/L1OpUSDCBridgeAdapter.sol | 7 +-- src/contracts/L2OpUSDCBridgeAdapter.sol | 7 +-- .../universal/OpUSDCBridgeAdapter.sol | 32 ++++++++-- src/interfaces/IOpUSDCBridgeAdapter.sol | 15 +++++ test/unit/OpUSDCBridgeAdapter.t.sol | 9 ++- test/utils/Helpers.sol | 16 ++++- test/utils/SigUtils.sol | 61 +++++++++++++++++++ 7 files changed, 130 insertions(+), 17 deletions(-) create mode 100644 test/utils/SigUtils.sol diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index 42a32802..5b1e42f6 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -249,11 +249,10 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Ensure the deadline has not passed if (block.timestamp > _deadline) revert IOpUSDCBridgeAdapter_MessageExpired(); - // Hash the message - bytes32 _messageHash = - keccak256(abi.encode(address(this), block.chainid, _to, _amount, _deadline, _minGasLimit, _nonce)); + BridgeMessage memory _message = + BridgeMessage({to: _to, amount: _amount, deadline: _deadline, nonce: _nonce, minGasLimit: _minGasLimit}); - _checkSignature(_signer, _messageHash, _signature); + _checkSignature(_signer, _hashMessageStruct(_message), _signature); // Mark the nonce as used userNonces[_signer][_nonce] = true; diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index db5ab3cf..f42ff027 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -193,11 +193,10 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Ensure the deadline has not passed if (block.timestamp > _deadline) revert IOpUSDCBridgeAdapter_MessageExpired(); - // Hash the message - bytes32 _messageHash = - keccak256(abi.encode(address(this), block.chainid, _to, _amount, _deadline, _minGasLimit, _nonce)); + BridgeMessage memory _message = + BridgeMessage({to: _to, amount: _amount, deadline: _deadline, nonce: _nonce, minGasLimit: _minGasLimit}); - _checkSignature(_signer, _messageHash, _signature); + _checkSignature(_signer, _hashMessageStruct(_message), _signature); // Mark the nonce as used userNonces[_signer][_nonce] = true; diff --git a/src/contracts/universal/OpUSDCBridgeAdapter.sol b/src/contracts/universal/OpUSDCBridgeAdapter.sol index 7c10fc77..ce53ca3d 100644 --- a/src/contracts/universal/OpUSDCBridgeAdapter.sol +++ b/src/contracts/universal/OpUSDCBridgeAdapter.sol @@ -2,14 +2,20 @@ pragma solidity 0.8.25; import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; + +import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol'; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; -abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { +abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable, EIP712 { using MessageHashUtils for bytes32; using SignatureChecker for address; + /// @notice The typehash for the bridge message + bytes32 public constant BRIDGE_MESSAGE_TYPEHASH = + keccak256('BridgeMessage(address to,uint256 amount,uint256 deadline,uint256 nonce,uint32 minGasLimit)'); + /// @inheritdoc IOpUSDCBridgeAdapter address public immutable USDC; @@ -32,8 +38,13 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { * @param _linkedAdapter The address of the linked adapter * @param _owner The address of the owner of the contract */ - // solhint-disable-next-line no-unused-vars - constructor(address _usdc, address _messenger, address _linkedAdapter, address _owner) Ownable(_owner) { + constructor( + address _usdc, + address _messenger, + address _linkedAdapter, + // solhint-disable-next-line no-unused-vars + address _owner + ) Ownable(_owner) EIP712('OpUSDCBridgeAdapter', '1.0.0') { USDC = _usdc; MESSENGER = _messenger; LINKED_ADAPTER = _linkedAdapter; @@ -100,8 +111,21 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { * @param _signature the signature of the message */ function _checkSignature(address _signer, bytes32 _messageHash, bytes memory _signature) internal view { - _messageHash = _messageHash.toEthSignedMessageHash(); + _messageHash = _hashTypedDataV4(_messageHash); if (!_signer.isValidSignatureNow(_messageHash, _signature)) revert IOpUSDCBridgeAdapter_InvalidSignature(); } + + /** + * @notice Hashes the bridge message struct + * @param _message The bridge message struct to hash + * @return _hash The hash of the bridge message struct + */ + function _hashMessageStruct(BridgeMessage memory _message) internal pure returns (bytes32 _hash) { + _hash = keccak256( + abi.encode( + BRIDGE_MESSAGE_TYPEHASH, _message.to, _message.amount, _message.deadline, _message.nonce, _message.minGasLimit + ) + ); + } } diff --git a/src/interfaces/IOpUSDCBridgeAdapter.sol b/src/interfaces/IOpUSDCBridgeAdapter.sol index 44c0fc00..2b080f1d 100644 --- a/src/interfaces/IOpUSDCBridgeAdapter.sol +++ b/src/interfaces/IOpUSDCBridgeAdapter.sol @@ -2,6 +2,21 @@ pragma solidity 0.8.25; interface IOpUSDCBridgeAdapter { + /** + * @notice The struct to hold the data for a bridge message with signature + * @param to The target address on the destination chain + * @param amount The amount of tokens to send + * @param deadline The deadline for the message to be executed + * @param nonce The nonce of the user + * @param minGasLimit The minimum gas limit for the message to be executed + */ + struct BridgeMessage { + address to; + uint256 amount; + uint256 deadline; + uint256 nonce; + uint32 minGasLimit; + } /*/////////////////////////////////////////////////////////////// EVENTS ///////////////////////////////////////////////////////////////*/ diff --git a/test/unit/OpUSDCBridgeAdapter.t.sol b/test/unit/OpUSDCBridgeAdapter.t.sol index 2b3d8f33..5a56dc68 100644 --- a/test/unit/OpUSDCBridgeAdapter.t.sol +++ b/test/unit/OpUSDCBridgeAdapter.t.sol @@ -5,6 +5,7 @@ import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/Messa import {OpUSDCBridgeAdapter} from 'contracts/universal/OpUSDCBridgeAdapter.sol'; import {Test} from 'forge-std/Test.sol'; import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; +import {SigUtils} from 'test/utils/SigUtils.sol'; contract ForTestOpUSDCBridgeAdapter is OpUSDCBridgeAdapter { constructor( @@ -109,10 +110,12 @@ contract OpUSDCBridgeAdapter_Unit_CheckSignature is Base { /** * @notice Check that the signature is valid */ - function test_validSignature(bytes memory _message) public { + function test_validSignature(IOpUSDCBridgeAdapter.BridgeMessage memory _message) public { + SigUtils _sigUtils = new SigUtils(address(adapter)); + vm.startPrank(_signerAd); - bytes32 _hashedMessage = keccak256(abi.encodePacked(_message)); - bytes32 _digest = MessageHashUtils.toEthSignedMessageHash(_hashedMessage); + bytes32 _hashedMessage = _sigUtils.getBridgeMessageHash(_message); + bytes32 _digest = _sigUtils.getTypedBridgeMessageHash(_message); (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPk, _digest); bytes memory _signature = abi.encodePacked(r, s, v); vm.stopPrank(); diff --git a/test/utils/Helpers.sol b/test/utils/Helpers.sol index 8d387084..b1c10499 100644 --- a/test/utils/Helpers.sol +++ b/test/utils/Helpers.sol @@ -3,6 +3,9 @@ pragma solidity ^0.8.25; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {Test} from 'forge-std/Test.sol'; +import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; + +import {SigUtils} from 'test/utils/SigUtils.sol'; contract Helpers is Test { using MessageHashUtils for bytes32; @@ -31,9 +34,18 @@ contract Helpers is Test { uint256 _signerPk, address _adapter ) internal returns (bytes memory _signature) { + IOpUSDCBridgeAdapter.BridgeMessage memory _message = IOpUSDCBridgeAdapter.BridgeMessage({ + to: _to, + amount: _amount, + deadline: _deadline, + nonce: _nonce, + minGasLimit: uint32(_minGasLimit) + }); + + SigUtils _sigUtils = new SigUtils(_adapter); + vm.startPrank(_signerAd); - bytes32 _digest = keccak256(abi.encode(_adapter, block.chainid, _to, _amount, _deadline, _minGasLimit, _nonce)) - .toEthSignedMessageHash(); + bytes32 _digest = SigUtils(_sigUtils).getTypedBridgeMessageHash(_message); (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPk, _digest); _signature = abi.encodePacked(r, s, v); vm.stopPrank(); diff --git a/test/utils/SigUtils.sol b/test/utils/SigUtils.sol new file mode 100644 index 00000000..4a4956d6 --- /dev/null +++ b/test/utils/SigUtils.sol @@ -0,0 +1,61 @@ +pragma solidity 0.8.25; + +import {ShortString, ShortStrings} from '@openzeppelin/contracts/utils/ShortStrings.sol'; +import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; + +contract SigUtils { + using ShortStrings for *; + + bytes32 private constant _TYPE_HASH = + keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); + bytes32 public constant BRIDGE_MESSAGE_TYPEHASH = + keccak256('BridgeMessage(address to,uint256 amount,uint256 deadline,uint256 nonce,uint32 minGasLimit)'); + + bytes32 internal immutable _DOMAIN_SEPARATOR; + + bytes32 private immutable _HASHED_NAME; + bytes32 private immutable _HASHED_VERSION; + + ShortString private immutable _NAME; + ShortString private immutable _VERSION; + string private _nameFallback; + string private _versionFallback; + + constructor(address _adapter) { + string memory _name = 'OpUSDCBridgeAdapter'; + string memory _version = '1.0.0'; + _NAME = _name.toShortStringWithFallback(_nameFallback); + _VERSION = _version.toShortStringWithFallback(_versionFallback); + + _HASHED_NAME = keccak256(bytes(_name)); + _HASHED_VERSION = keccak256(bytes(_version)); + + _DOMAIN_SEPARATOR = keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, block.chainid, _adapter)); + } + + /** + * @notice Hashes the bridge message struct + * @param _message The bridge message struct to hash + * @return _hash The hash of the bridge message struct + */ + function getBridgeMessageHash(IOpUSDCBridgeAdapter.BridgeMessage memory _message) public view returns (bytes32 _hash) { + _hash = keccak256( + abi.encode( + BRIDGE_MESSAGE_TYPEHASH, _message.to, _message.amount, _message.deadline, _message.nonce, _message.minGasLimit + ) + ); + } + + /** + * @notice Hashes the bridge message struct and returns the EIP712 hash + * @param _message The bridge message struct to hash + * @return _hash The hash of the bridge message struct + */ + function getTypedBridgeMessageHash(IOpUSDCBridgeAdapter.BridgeMessage memory _message) + public + view + returns (bytes32 _hash) + { + _hash = keccak256(abi.encodePacked('\x19\x01', _DOMAIN_SEPARATOR, getBridgeMessageHash(_message))); + } +} From a591a953b35f34579d8367fa38c0f3e1bfc60ac6 Mon Sep 17 00:00:00 2001 From: excaliborr Date: Thu, 25 Jul 2024 10:31:05 -0400 Subject: [PATCH 18/23] Revert "fix: eip-712 compliance" This reverts commit 3bb8d4b006cf508b549bd0ac4dce24de0c0cecbb. --- src/contracts/L1OpUSDCBridgeAdapter.sol | 7 ++- src/contracts/L2OpUSDCBridgeAdapter.sol | 7 ++- .../universal/OpUSDCBridgeAdapter.sol | 32 ++-------- src/interfaces/IOpUSDCBridgeAdapter.sol | 15 ----- test/unit/OpUSDCBridgeAdapter.t.sol | 9 +-- test/utils/Helpers.sol | 16 +---- test/utils/SigUtils.sol | 61 ------------------- 7 files changed, 17 insertions(+), 130 deletions(-) delete mode 100644 test/utils/SigUtils.sol diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index 5b1e42f6..42a32802 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -249,10 +249,11 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Ensure the deadline has not passed if (block.timestamp > _deadline) revert IOpUSDCBridgeAdapter_MessageExpired(); - BridgeMessage memory _message = - BridgeMessage({to: _to, amount: _amount, deadline: _deadline, nonce: _nonce, minGasLimit: _minGasLimit}); + // Hash the message + bytes32 _messageHash = + keccak256(abi.encode(address(this), block.chainid, _to, _amount, _deadline, _minGasLimit, _nonce)); - _checkSignature(_signer, _hashMessageStruct(_message), _signature); + _checkSignature(_signer, _messageHash, _signature); // Mark the nonce as used userNonces[_signer][_nonce] = true; diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index f42ff027..db5ab3cf 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -193,10 +193,11 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { // Ensure the deadline has not passed if (block.timestamp > _deadline) revert IOpUSDCBridgeAdapter_MessageExpired(); - BridgeMessage memory _message = - BridgeMessage({to: _to, amount: _amount, deadline: _deadline, nonce: _nonce, minGasLimit: _minGasLimit}); + // Hash the message + bytes32 _messageHash = + keccak256(abi.encode(address(this), block.chainid, _to, _amount, _deadline, _minGasLimit, _nonce)); - _checkSignature(_signer, _hashMessageStruct(_message), _signature); + _checkSignature(_signer, _messageHash, _signature); // Mark the nonce as used userNonces[_signer][_nonce] = true; diff --git a/src/contracts/universal/OpUSDCBridgeAdapter.sol b/src/contracts/universal/OpUSDCBridgeAdapter.sol index ce53ca3d..7c10fc77 100644 --- a/src/contracts/universal/OpUSDCBridgeAdapter.sol +++ b/src/contracts/universal/OpUSDCBridgeAdapter.sol @@ -2,20 +2,14 @@ pragma solidity 0.8.25; import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; - -import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol'; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; -abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable, EIP712 { +abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable { using MessageHashUtils for bytes32; using SignatureChecker for address; - /// @notice The typehash for the bridge message - bytes32 public constant BRIDGE_MESSAGE_TYPEHASH = - keccak256('BridgeMessage(address to,uint256 amount,uint256 deadline,uint256 nonce,uint32 minGasLimit)'); - /// @inheritdoc IOpUSDCBridgeAdapter address public immutable USDC; @@ -38,13 +32,8 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable, EIP712 { * @param _linkedAdapter The address of the linked adapter * @param _owner The address of the owner of the contract */ - constructor( - address _usdc, - address _messenger, - address _linkedAdapter, - // solhint-disable-next-line no-unused-vars - address _owner - ) Ownable(_owner) EIP712('OpUSDCBridgeAdapter', '1.0.0') { + // solhint-disable-next-line no-unused-vars + constructor(address _usdc, address _messenger, address _linkedAdapter, address _owner) Ownable(_owner) { USDC = _usdc; MESSENGER = _messenger; LINKED_ADAPTER = _linkedAdapter; @@ -111,21 +100,8 @@ abstract contract OpUSDCBridgeAdapter is IOpUSDCBridgeAdapter, Ownable, EIP712 { * @param _signature the signature of the message */ function _checkSignature(address _signer, bytes32 _messageHash, bytes memory _signature) internal view { - _messageHash = _hashTypedDataV4(_messageHash); + _messageHash = _messageHash.toEthSignedMessageHash(); if (!_signer.isValidSignatureNow(_messageHash, _signature)) revert IOpUSDCBridgeAdapter_InvalidSignature(); } - - /** - * @notice Hashes the bridge message struct - * @param _message The bridge message struct to hash - * @return _hash The hash of the bridge message struct - */ - function _hashMessageStruct(BridgeMessage memory _message) internal pure returns (bytes32 _hash) { - _hash = keccak256( - abi.encode( - BRIDGE_MESSAGE_TYPEHASH, _message.to, _message.amount, _message.deadline, _message.nonce, _message.minGasLimit - ) - ); - } } diff --git a/src/interfaces/IOpUSDCBridgeAdapter.sol b/src/interfaces/IOpUSDCBridgeAdapter.sol index 2b080f1d..44c0fc00 100644 --- a/src/interfaces/IOpUSDCBridgeAdapter.sol +++ b/src/interfaces/IOpUSDCBridgeAdapter.sol @@ -2,21 +2,6 @@ pragma solidity 0.8.25; interface IOpUSDCBridgeAdapter { - /** - * @notice The struct to hold the data for a bridge message with signature - * @param to The target address on the destination chain - * @param amount The amount of tokens to send - * @param deadline The deadline for the message to be executed - * @param nonce The nonce of the user - * @param minGasLimit The minimum gas limit for the message to be executed - */ - struct BridgeMessage { - address to; - uint256 amount; - uint256 deadline; - uint256 nonce; - uint32 minGasLimit; - } /*/////////////////////////////////////////////////////////////// EVENTS ///////////////////////////////////////////////////////////////*/ diff --git a/test/unit/OpUSDCBridgeAdapter.t.sol b/test/unit/OpUSDCBridgeAdapter.t.sol index 5a56dc68..2b3d8f33 100644 --- a/test/unit/OpUSDCBridgeAdapter.t.sol +++ b/test/unit/OpUSDCBridgeAdapter.t.sol @@ -5,7 +5,6 @@ import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/Messa import {OpUSDCBridgeAdapter} from 'contracts/universal/OpUSDCBridgeAdapter.sol'; import {Test} from 'forge-std/Test.sol'; import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; -import {SigUtils} from 'test/utils/SigUtils.sol'; contract ForTestOpUSDCBridgeAdapter is OpUSDCBridgeAdapter { constructor( @@ -110,12 +109,10 @@ contract OpUSDCBridgeAdapter_Unit_CheckSignature is Base { /** * @notice Check that the signature is valid */ - function test_validSignature(IOpUSDCBridgeAdapter.BridgeMessage memory _message) public { - SigUtils _sigUtils = new SigUtils(address(adapter)); - + function test_validSignature(bytes memory _message) public { vm.startPrank(_signerAd); - bytes32 _hashedMessage = _sigUtils.getBridgeMessageHash(_message); - bytes32 _digest = _sigUtils.getTypedBridgeMessageHash(_message); + bytes32 _hashedMessage = keccak256(abi.encodePacked(_message)); + bytes32 _digest = MessageHashUtils.toEthSignedMessageHash(_hashedMessage); (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPk, _digest); bytes memory _signature = abi.encodePacked(r, s, v); vm.stopPrank(); diff --git a/test/utils/Helpers.sol b/test/utils/Helpers.sol index b1c10499..8d387084 100644 --- a/test/utils/Helpers.sol +++ b/test/utils/Helpers.sol @@ -3,9 +3,6 @@ pragma solidity ^0.8.25; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {Test} from 'forge-std/Test.sol'; -import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; - -import {SigUtils} from 'test/utils/SigUtils.sol'; contract Helpers is Test { using MessageHashUtils for bytes32; @@ -34,18 +31,9 @@ contract Helpers is Test { uint256 _signerPk, address _adapter ) internal returns (bytes memory _signature) { - IOpUSDCBridgeAdapter.BridgeMessage memory _message = IOpUSDCBridgeAdapter.BridgeMessage({ - to: _to, - amount: _amount, - deadline: _deadline, - nonce: _nonce, - minGasLimit: uint32(_minGasLimit) - }); - - SigUtils _sigUtils = new SigUtils(_adapter); - vm.startPrank(_signerAd); - bytes32 _digest = SigUtils(_sigUtils).getTypedBridgeMessageHash(_message); + bytes32 _digest = keccak256(abi.encode(_adapter, block.chainid, _to, _amount, _deadline, _minGasLimit, _nonce)) + .toEthSignedMessageHash(); (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPk, _digest); _signature = abi.encodePacked(r, s, v); vm.stopPrank(); diff --git a/test/utils/SigUtils.sol b/test/utils/SigUtils.sol deleted file mode 100644 index 4a4956d6..00000000 --- a/test/utils/SigUtils.sol +++ /dev/null @@ -1,61 +0,0 @@ -pragma solidity 0.8.25; - -import {ShortString, ShortStrings} from '@openzeppelin/contracts/utils/ShortStrings.sol'; -import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol'; - -contract SigUtils { - using ShortStrings for *; - - bytes32 private constant _TYPE_HASH = - keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); - bytes32 public constant BRIDGE_MESSAGE_TYPEHASH = - keccak256('BridgeMessage(address to,uint256 amount,uint256 deadline,uint256 nonce,uint32 minGasLimit)'); - - bytes32 internal immutable _DOMAIN_SEPARATOR; - - bytes32 private immutable _HASHED_NAME; - bytes32 private immutable _HASHED_VERSION; - - ShortString private immutable _NAME; - ShortString private immutable _VERSION; - string private _nameFallback; - string private _versionFallback; - - constructor(address _adapter) { - string memory _name = 'OpUSDCBridgeAdapter'; - string memory _version = '1.0.0'; - _NAME = _name.toShortStringWithFallback(_nameFallback); - _VERSION = _version.toShortStringWithFallback(_versionFallback); - - _HASHED_NAME = keccak256(bytes(_name)); - _HASHED_VERSION = keccak256(bytes(_version)); - - _DOMAIN_SEPARATOR = keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, block.chainid, _adapter)); - } - - /** - * @notice Hashes the bridge message struct - * @param _message The bridge message struct to hash - * @return _hash The hash of the bridge message struct - */ - function getBridgeMessageHash(IOpUSDCBridgeAdapter.BridgeMessage memory _message) public view returns (bytes32 _hash) { - _hash = keccak256( - abi.encode( - BRIDGE_MESSAGE_TYPEHASH, _message.to, _message.amount, _message.deadline, _message.nonce, _message.minGasLimit - ) - ); - } - - /** - * @notice Hashes the bridge message struct and returns the EIP712 hash - * @param _message The bridge message struct to hash - * @return _hash The hash of the bridge message struct - */ - function getTypedBridgeMessageHash(IOpUSDCBridgeAdapter.BridgeMessage memory _message) - public - view - returns (bytes32 _hash) - { - _hash = keccak256(abi.encodePacked('\x19\x01', _DOMAIN_SEPARATOR, getBridgeMessageHash(_message))); - } -} From 3111a0da90ee108710d2a10a89d803cd2d6b205c Mon Sep 17 00:00:00 2001 From: Hex <165055168+hexshire@users.noreply.github.com> Date: Thu, 25 Jul 2024 12:19:22 -0300 Subject: [PATCH 19/23] Update src/contracts/L2OpUSDCBridgeAdapter.sol Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> --- src/contracts/L2OpUSDCBridgeAdapter.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 261820c9..f3d30c3e 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -211,7 +211,8 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { if (messengerStatus == Status.Deprecated) { // Return the funds to the spender incase the target on L2 is a contract that can´t handle the funds on L1 ICrossDomainMessenger(MESSENGER).sendMessage( - LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), 150_000 + uint256 _minGasLimit = 150_000; + LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), _minGasLimit ); } else { // Mint the tokens to the user From 86141df14a42edc8e2a24564eb7f71ee8cbe7650 Mon Sep 17 00:00:00 2001 From: hexshire Date: Thu, 25 Jul 2024 12:24:04 -0300 Subject: [PATCH 20/23] refactor: readability --- src/contracts/L2OpUSDCBridgeAdapter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index f3d30c3e..9909b0d5 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -209,9 +209,9 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { */ function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter { if (messengerStatus == Status.Deprecated) { + uint32 _minGasLimit = 150_000; // Return the funds to the spender incase the target on L2 is a contract that can´t handle the funds on L1 ICrossDomainMessenger(MESSENGER).sendMessage( - uint256 _minGasLimit = 150_000; LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), _minGasLimit ); } else { From 4cf8ef34ff374e394d803513593673c063eeb5e3 Mon Sep 17 00:00:00 2001 From: hexshire Date: Thu, 25 Jul 2024 12:37:39 -0300 Subject: [PATCH 21/23] chore: add param name --- src/contracts/L1OpUSDCBridgeAdapter.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index a4221c99..a1ec36f4 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -250,9 +250,11 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { * @notice Receive the message from the other chain and transfer the tokens to the user * @dev This function should only be called when receiving a message to transfer the tokens * @param _user The user to transfer the tokens to + * @param _spender unused parameter on L1, added for maintainability * @param _amount The amount of tokens to transfer */ - function receiveMessage(address _user, address, uint256 _amount) external override onlyLinkedAdapter { + // solhint-disable-next-line no-unused-vars + function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter { // Transfer the tokens to the user try this.attemptTransfer(_user, _amount) { emit MessageReceived(_user, _amount, MESSENGER); From b3fc4541c211862790954235ded1affbd96224cc Mon Sep 17 00:00:00 2001 From: hexshire Date: Thu, 25 Jul 2024 12:42:08 -0300 Subject: [PATCH 22/23] test: rename test case --- test/unit/L2OpUSDCBridgeAdapter.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/L2OpUSDCBridgeAdapter.t.sol b/test/unit/L2OpUSDCBridgeAdapter.t.sol index cce4cf68..58a4b867 100644 --- a/test/unit/L2OpUSDCBridgeAdapter.t.sol +++ b/test/unit/L2OpUSDCBridgeAdapter.t.sol @@ -700,7 +700,7 @@ contract L2OpUSDCBridgeAdapter_Unit_ReceiveMessage is Base { /** * @notice Check that the function returns the funds if the contract is deprecated */ - function test_revertIfMigratedToNative(uint256 _amount) external { + function test_refundSpenderAfterMigration(uint256 _amount) external { adapter.forTest_setMessengerStatus(IOpUSDCBridgeAdapter.Status.Deprecated); // Mock calls vm.mockCall(_messenger, abi.encodeWithSignature('xDomainMessageSender()'), abi.encode(_linkedAdapter)); From 1063e6e6e09142d7e127b88ea95d0dd788ef760c Mon Sep 17 00:00:00 2001 From: hexshire Date: Thu, 25 Jul 2024 12:52:21 -0300 Subject: [PATCH 23/23] chore: add natspec --- src/contracts/L1OpUSDCBridgeAdapter.sol | 7 +++++++ src/contracts/L2OpUSDCBridgeAdapter.sol | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/contracts/L1OpUSDCBridgeAdapter.sol b/src/contracts/L1OpUSDCBridgeAdapter.sol index a1ec36f4..177980db 100644 --- a/src/contracts/L1OpUSDCBridgeAdapter.sol +++ b/src/contracts/L1OpUSDCBridgeAdapter.sol @@ -294,6 +294,13 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { /*/////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS ///////////////////////////////////////////////////////////////*/ + /** + * @notice Send the message to the linked adapter + * @param _from address that originated the message + * @param _to target address on the destination chain + * @param _amount amount of tokens to be bridged + * @param _minGasLimit minimum gas limit for the other chain to execute the message + */ function _sendMessage(address _from, address _to, uint256 _amount, uint32 _minGasLimit) internal { // Transfer the tokens to the contract IUSDC(USDC).safeTransferFrom(_from, address(this), _amount); diff --git a/src/contracts/L2OpUSDCBridgeAdapter.sol b/src/contracts/L2OpUSDCBridgeAdapter.sol index 9909b0d5..14bd6fe4 100644 --- a/src/contracts/L2OpUSDCBridgeAdapter.sol +++ b/src/contracts/L2OpUSDCBridgeAdapter.sol @@ -280,6 +280,13 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter { /*/////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS ///////////////////////////////////////////////////////////////*/ + /** + * @notice Send the message to the linked adapter + * @param _from address that originated the message + * @param _to target address on the destination chain + * @param _amount amount of tokens to be bridged + * @param _minGasLimit minimum gas limit for the other chain to execute the message + */ function _sendMessage(address _from, address _to, uint256 _amount, uint32 _minGasLimit) internal { IUSDC(USDC).safeTransferFrom(_from, address(this), _amount);