diff --git a/.gitmodules b/.gitmodules index 888d42d..e80ffd8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/openzeppelin/openzeppelin-contracts diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 0000000..dbb6104 --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 diff --git a/src/receivers/AMBReceiver.sol b/src/receivers/AMBReceiver.sol index df285b4..f9f3cb1 100644 --- a/src/receivers/AMBReceiver.sol +++ b/src/receivers/AMBReceiver.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.0; +import { Address } from "lib/openzeppelin-contracts/contracts/utils/Address.sol"; + interface IArbitraryMessagingBridge { function messageSender() external view returns (address); function messageSourceChainId() external view returns (bytes32); @@ -12,6 +14,8 @@ interface IArbitraryMessagingBridge { */ contract AMBReceiver { + using Address for address; + address public immutable amb; bytes32 public immutable sourceChainId; address public immutable sourceAuthority; @@ -29,17 +33,12 @@ contract AMBReceiver { target = _target; } - function forward(bytes memory message) external { + fallback(bytes calldata message) external returns (bytes memory) { require(msg.sender == amb, "AMBReceiver/invalid-sender"); require(IArbitraryMessagingBridge(amb).messageSourceChainId() == sourceChainId, "AMBReceiver/invalid-sourceChainId"); require(IArbitraryMessagingBridge(amb).messageSender() == sourceAuthority, "AMBReceiver/invalid-sourceAuthority"); - (bool success, bytes memory ret) = target.call(message); - if (!success) { - assembly { - revert(add(ret, 0x20), mload(ret)) - } - } + return target.functionCall(message); } } diff --git a/src/receivers/ArbitrumReceiver.sol b/src/receivers/ArbitrumReceiver.sol index 4f48127..1807551 100644 --- a/src/receivers/ArbitrumReceiver.sol +++ b/src/receivers/ArbitrumReceiver.sol @@ -1,12 +1,16 @@ // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.0; +import { Address } from "lib/openzeppelin-contracts/contracts/utils/Address.sol"; + /** * @title ArbitrumReceiver * @notice Receive messages to an Arbitrum-style chain. */ contract ArbitrumReceiver { + using Address for address; + address public immutable l1Authority; address public immutable target; @@ -24,15 +28,10 @@ contract ArbitrumReceiver { } } - function forward(bytes memory message) external { + fallback(bytes calldata message) external returns (bytes memory) { require(_getL1MessageSender() == l1Authority, "ArbitrumReceiver/invalid-l1Authority"); - (bool success, bytes memory ret) = target.call(message); - if (!success) { - assembly { - revert(add(ret, 0x20), mload(ret)) - } - } + return target.functionCall(message); } } diff --git a/src/receivers/CCTPReceiver.sol b/src/receivers/CCTPReceiver.sol index 04bc204..0ca5b7c 100644 --- a/src/receivers/CCTPReceiver.sol +++ b/src/receivers/CCTPReceiver.sol @@ -1,12 +1,16 @@ // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.0; +import { Address } from "lib/openzeppelin-contracts/contracts/utils/Address.sol"; + /** * @title CCTPReceiver * @notice Receive messages from CCTP-style bridge. */ contract CCTPReceiver { + using Address for address; + address public immutable destinationMessenger; uint32 public immutable sourceDomainId; bytes32 public immutable sourceAuthority; @@ -33,12 +37,7 @@ contract CCTPReceiver { require(sourceDomainId == sourceDomain, "CCTPReceiver/invalid-sourceDomain"); require(sender == sourceAuthority, "CCTPReceiver/invalid-sourceAuthority"); - (bool success, bytes memory ret) = target.call(messageBody); - if (!success) { - assembly { - revert(add(ret, 0x20), mload(ret)) - } - } + target.functionCall(messageBody); return true; } diff --git a/src/receivers/OptimismReceiver.sol b/src/receivers/OptimismReceiver.sol index 65c524d..ec39e95 100644 --- a/src/receivers/OptimismReceiver.sol +++ b/src/receivers/OptimismReceiver.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.0; +import { Address } from "lib/openzeppelin-contracts/contracts/utils/Address.sol"; + interface ICrossDomainOptimism { function xDomainMessageSender() external view returns (address); } @@ -11,6 +13,8 @@ interface ICrossDomainOptimism { */ contract OptimismReceiver { + using Address for address; + ICrossDomainOptimism public constant l2CrossDomain = ICrossDomainOptimism(0x4200000000000000000000000000000000000007); address public immutable l1Authority; @@ -24,16 +28,11 @@ contract OptimismReceiver { target = _target; } - function forward(bytes memory message) external { + fallback(bytes calldata message) external returns (bytes memory) { require(msg.sender == address(l2CrossDomain), "OptimismReceiver/invalid-sender"); require(l2CrossDomain.xDomainMessageSender() == l1Authority, "OptimismReceiver/invalid-l1Authority"); - (bool success, bytes memory ret) = target.call(message); - if (!success) { - assembly { - revert(add(ret, 0x20), mload(ret)) - } - } + return target.functionCall(message); } } diff --git a/test/ArbitrumIntegration.t.sol b/test/ArbitrumIntegration.t.sol index f7a2037..6ef0e77 100644 --- a/test/ArbitrumIntegration.t.sol +++ b/test/ArbitrumIntegration.t.sol @@ -57,7 +57,7 @@ contract ArbitrumIntegrationTest is IntegrationBaseTest { ArbitrumForwarder.sendMessageL1toL2( bridge.sourceCrossChainMessenger, destinationReceiver, - abi.encodeCall(ArbitrumReceiver.forward, (message)), + message, 100000, 1 gwei, block.basefee + 10 gwei diff --git a/test/GnosisIntegration.t.sol b/test/GnosisIntegration.t.sol index bf08229..2703b7d 100644 --- a/test/GnosisIntegration.t.sol +++ b/test/GnosisIntegration.t.sol @@ -32,7 +32,7 @@ contract GnosisIntegrationTest is IntegrationBaseTest { vm.prank(randomAddress); vm.expectRevert("AMBReceiver/invalid-sender"); - AMBReceiver(destinationReceiver).forward(abi.encodeCall(MessageOrdering.push, (1))); + MessageOrdering(destinationReceiver).push(1); } function test_invalidSourceChainId() public { @@ -76,7 +76,7 @@ contract GnosisIntegrationTest is IntegrationBaseTest { function queueSourceToDestination(bytes memory message) internal override { AMBForwarder.sendMessageEthereumToGnosisChain( destinationReceiver, - abi.encodeCall(AMBReceiver.forward, (message)), + message, 100000 ); } @@ -84,7 +84,7 @@ contract GnosisIntegrationTest is IntegrationBaseTest { function queueDestinationToSource(bytes memory message) internal override { AMBForwarder.sendMessageGnosisChainToEthereum( sourceReceiver, - abi.encodeCall(AMBReceiver.forward, (message)), + message, 100000 ); } diff --git a/test/OptimismIntegration.t.sol b/test/OptimismIntegration.t.sol index a2c2f8c..8043136 100644 --- a/test/OptimismIntegration.t.sol +++ b/test/OptimismIntegration.t.sol @@ -36,7 +36,7 @@ contract OptimismIntegrationTest is IntegrationBaseTest { vm.prank(randomAddress); vm.expectRevert("OptimismReceiver/invalid-sender"); - OptimismReceiver(destinationReceiver).forward(abi.encodeCall(MessageOrdering.push, (1))); + MessageOrdering(destinationReceiver).push(1); } function test_optimism() public { @@ -63,7 +63,7 @@ contract OptimismIntegrationTest is IntegrationBaseTest { OptimismForwarder.sendMessageL1toL2( bridge.sourceCrossChainMessenger, destinationReceiver, - abi.encodeCall(OptimismReceiver.forward, (message)), + message, 100000 ); }