From 9d081f173c7db76d1141bb0f5794bdf5074f00d7 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Wed, 5 Jun 2024 17:59:26 +0900 Subject: [PATCH 01/10] add unit tests for amb receiver --- test/AMBReceiver.t.sol | 113 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 test/AMBReceiver.t.sol diff --git a/test/AMBReceiver.t.sol b/test/AMBReceiver.t.sol new file mode 100644 index 0000000..1d232a1 --- /dev/null +++ b/test/AMBReceiver.t.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; + +import { AMBReceiver } from "src/receivers/AMBReceiver.sol"; + +contract AMBMock { + + bytes32 public messageSourceChainId; + address public messageSender; + + constructor(bytes32 _messageSourceChainId, address _messageSender) { + messageSourceChainId = _messageSourceChainId; + messageSender = _messageSender; + } + + function __setSourceChainId(bytes32 _messageSourceChainId) public { + messageSourceChainId = _messageSourceChainId; + } + + function __setSender(address _messageSender) public { + messageSender = _messageSender; + } + +} + +contract TargetContractMock { + + uint256 public s; + + function someFunc() external { + s++; + } + + function revertFunc() external pure { + revert("error"); + } + +} + +contract AMBReceiverTest is Test { + + AMBMock amb; + TargetContractMock target; + + AMBReceiver receiver; + + bytes32 sourceChainId = bytes32(uint256(1)); + address sourceAuthority = makeAddr("sourceAuthority"); + address randomAddress = makeAddr("randomAddress"); + + function setUp() public { + amb = new AMBMock(sourceChainId, sourceAuthority); + target = new TargetContractMock(); + + receiver = new AMBReceiver( + address(amb), + sourceChainId, + sourceAuthority, + address(target) + ); + } + + function test_constructor() public { + receiver = new AMBReceiver( + address(amb), + sourceChainId, + sourceAuthority, + address(target) + ); + + assertEq(receiver.amb(), address(amb)); + assertEq(receiver.sourceChainId(), sourceChainId); + assertEq(receiver.sourceAuthority(), sourceAuthority); + assertEq(receiver.target(), address(target)); + } + + function test_forward_invalidSender() public { + vm.prank(randomAddress); + vm.expectRevert("AMBReceiver/invalid-sender"); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + } + + function test_forward_invalidSourceChainId() public { + amb.__setSourceChainId(bytes32(uint256(2))); + + vm.prank(address(amb)); + vm.expectRevert("AMBReceiver/invalid-sourceChainId"); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + } + + function test_forward_invalidSourceAuthority() public { + amb.__setSender(randomAddress); + + vm.prank(address(amb)); + vm.expectRevert("AMBReceiver/invalid-sourceAuthority"); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + } + + function test_forward_success() public { + vm.prank(address(amb)); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + assertEq(target.s(), 1); + } + + function test_forward_revert() public { + vm.prank(address(amb)); + vm.expectRevert("error"); + receiver.forward(abi.encodeCall(TargetContractMock.revertFunc, ())); + } + +} From 747c4288b0cb1e1034f1b425794812966c0ca941 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Wed, 5 Jun 2024 19:03:09 +0900 Subject: [PATCH 02/10] add cctp unit test --- test/AMBReceiver.t.sol | 19 ++---- test/CCTPReceiver.t.sol | 97 +++++++++++++++++++++++++++++++ test/mocks/TargetContractMock.sol | 16 +++++ 3 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 test/CCTPReceiver.t.sol create mode 100644 test/mocks/TargetContractMock.sol diff --git a/test/AMBReceiver.t.sol b/test/AMBReceiver.t.sol index 1d232a1..b1b5986 100644 --- a/test/AMBReceiver.t.sol +++ b/test/AMBReceiver.t.sol @@ -3,6 +3,8 @@ pragma solidity >=0.8.0; import "forge-std/Test.sol"; +import { TargetContractMock } from "test/mocks/TargetContractMock.sol"; + import { AMBReceiver } from "src/receivers/AMBReceiver.sol"; contract AMBMock { @@ -25,20 +27,6 @@ contract AMBMock { } -contract TargetContractMock { - - uint256 public s; - - function someFunc() external { - s++; - } - - function revertFunc() external pure { - revert("error"); - } - -} - contract AMBReceiverTest is Test { AMBMock amb; @@ -99,9 +87,10 @@ contract AMBReceiverTest is Test { } function test_forward_success() public { + assertEq(target.data(), 0); vm.prank(address(amb)); receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); - assertEq(target.s(), 1); + assertEq(target.data(), 1); } function test_forward_revert() public { diff --git a/test/CCTPReceiver.t.sol b/test/CCTPReceiver.t.sol new file mode 100644 index 0000000..2c81175 --- /dev/null +++ b/test/CCTPReceiver.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; + +import { TargetContractMock } from "test/mocks/TargetContractMock.sol"; + +import { CCTPReceiver } from "src/receivers/CCTPReceiver.sol"; + +contract CCTPReceiverTest is Test { + + TargetContractMock target; + + CCTPReceiver receiver; + + address destinationMessenger = makeAddr("destinationMessenger"); + uint32 sourceDomainId = 1; + address sourceAuthority = makeAddr("sourceAuthority"); + address randomAddress = makeAddr("randomAddress"); + + function setUp() public { + target = new TargetContractMock(); + + receiver = new CCTPReceiver( + destinationMessenger, + sourceDomainId, + sourceAuthority, + address(target) + ); + } + + function test_constructor() public { + receiver = new CCTPReceiver( + destinationMessenger, + sourceDomainId, + sourceAuthority, + address(target) + ); + + assertEq(receiver.destinationMessenger(), destinationMessenger); + assertEq(receiver.sourceDomainId(), sourceDomainId); + assertEq(receiver.sourceAuthority(), sourceAuthority); + assertEq(receiver.target(), address(target)); + } + + function test_handleReceiveMessage_invalidSender() public { + vm.prank(randomAddress); + vm.expectRevert("CCTPReceiver/invalid-sender"); + receiver.handleReceiveMessage( + sourceDomainId, + bytes32(uint256(uint160(sourceAuthority))), + abi.encodeCall(TargetContractMock.someFunc, ()) + ); + } + + function test_handleReceiveMessage_invalidSourceChainId() public { + vm.prank(destinationMessenger); + vm.expectRevert("CCTPReceiver/invalid-sourceDomain"); + receiver.handleReceiveMessage( + 2, + bytes32(uint256(uint160(sourceAuthority))), + abi.encodeCall(TargetContractMock.someFunc, ()) + ); + } + + function test_handleReceiveMessage_invalidSourceAuthority() public { + vm.prank(destinationMessenger); + vm.expectRevert("CCTPReceiver/invalid-sourceAuthority"); + receiver.handleReceiveMessage( + sourceDomainId, + bytes32(uint256(uint160(randomAddress))), + abi.encodeCall(TargetContractMock.someFunc, ()) + ); + } + + function test_handleReceiveMessage_success() public { + assertEq(target.data(), 0); + vm.prank(destinationMessenger); + receiver.handleReceiveMessage( + sourceDomainId, + bytes32(uint256(uint160(sourceAuthority))), + abi.encodeCall(TargetContractMock.someFunc, ()) + ); + assertEq(target.data(), 1); + } + + function test_handleReceiveMessage_revert() public { + vm.prank(destinationMessenger); + vm.expectRevert("error"); + receiver.handleReceiveMessage( + sourceDomainId, + bytes32(uint256(uint160(sourceAuthority))), + abi.encodeCall(TargetContractMock.revertFunc, ()) + ); + } + +} diff --git a/test/mocks/TargetContractMock.sol b/test/mocks/TargetContractMock.sol new file mode 100644 index 0000000..77fddb0 --- /dev/null +++ b/test/mocks/TargetContractMock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity >=0.8.0; + +contract TargetContractMock { + + uint256 public data; + + function someFunc() external { + data++; + } + + function revertFunc() external pure { + revert("error"); + } + +} From 3fcbcce7ce31ab516c97762a9c9cd1f030e282f7 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Wed, 5 Jun 2024 19:08:54 +0900 Subject: [PATCH 03/10] update to new cctp receiver --- test/CCTPReceiver.t.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/CCTPReceiver.t.sol b/test/CCTPReceiver.t.sol index 2c81175..4f77c04 100644 --- a/test/CCTPReceiver.t.sol +++ b/test/CCTPReceiver.t.sol @@ -15,7 +15,7 @@ contract CCTPReceiverTest is Test { address destinationMessenger = makeAddr("destinationMessenger"); uint32 sourceDomainId = 1; - address sourceAuthority = makeAddr("sourceAuthority"); + bytes32 sourceAuthority = bytes32(uint256(uint160(makeAddr("sourceAuthority")))); address randomAddress = makeAddr("randomAddress"); function setUp() public { @@ -48,7 +48,7 @@ contract CCTPReceiverTest is Test { vm.expectRevert("CCTPReceiver/invalid-sender"); receiver.handleReceiveMessage( sourceDomainId, - bytes32(uint256(uint160(sourceAuthority))), + sourceAuthority, abi.encodeCall(TargetContractMock.someFunc, ()) ); } @@ -58,7 +58,7 @@ contract CCTPReceiverTest is Test { vm.expectRevert("CCTPReceiver/invalid-sourceDomain"); receiver.handleReceiveMessage( 2, - bytes32(uint256(uint160(sourceAuthority))), + sourceAuthority, abi.encodeCall(TargetContractMock.someFunc, ()) ); } @@ -78,7 +78,7 @@ contract CCTPReceiverTest is Test { vm.prank(destinationMessenger); receiver.handleReceiveMessage( sourceDomainId, - bytes32(uint256(uint160(sourceAuthority))), + sourceAuthority, abi.encodeCall(TargetContractMock.someFunc, ()) ); assertEq(target.data(), 1); @@ -89,7 +89,7 @@ contract CCTPReceiverTest is Test { vm.expectRevert("error"); receiver.handleReceiveMessage( sourceDomainId, - bytes32(uint256(uint160(sourceAuthority))), + sourceAuthority, abi.encodeCall(TargetContractMock.revertFunc, ()) ); } From 5669f7db781c83cc1782a474cc68493febcd19f8 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Wed, 5 Jun 2024 19:24:50 +0900 Subject: [PATCH 04/10] add arbitrum receiever unit tests --- test/ArbitrumReceiver.t.sol | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 test/ArbitrumReceiver.t.sol diff --git a/test/ArbitrumReceiver.t.sol b/test/ArbitrumReceiver.t.sol new file mode 100644 index 0000000..02d57c6 --- /dev/null +++ b/test/ArbitrumReceiver.t.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; + +import { TargetContractMock } from "test/mocks/TargetContractMock.sol"; + +import { ArbitrumReceiver } from "src/receivers/ArbitrumReceiver.sol"; + +contract ArbitrumReceiverTest is Test { + + TargetContractMock target; + + ArbitrumReceiver receiver; + + address sourceAuthority = makeAddr("sourceAuthority"); + address sourceAuthorityWithOffset; + address randomAddress = makeAddr("randomAddress"); + + function setUp() public { + target = new TargetContractMock(); + + receiver = new ArbitrumReceiver( + sourceAuthority, + address(target) + ); + unchecked { + sourceAuthorityWithOffset = address(uint160(sourceAuthority) + uint160(0x1111000000000000000000000000000000001111)); + } + } + + function test_constructor() public { + receiver = new ArbitrumReceiver( + sourceAuthority, + address(target) + ); + + assertEq(receiver.l1Authority(), sourceAuthority); + assertEq(receiver.target(), address(target)); + } + + function test_forward_invalidL1Authority() public { + vm.prank(randomAddress); + vm.expectRevert("ArbitrumReceiver/invalid-l1Authority"); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + } + + function test_forward_invalidL1AuthoritySourceAuthorityNoOffset() public { + vm.prank(sourceAuthority); + vm.expectRevert("ArbitrumReceiver/invalid-l1Authority"); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + } + + function test_forward_success() public { + assertEq(target.data(), 0); + vm.prank(sourceAuthorityWithOffset); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + assertEq(target.data(), 1); + } + + function test_forward_revert() public { + vm.prank(sourceAuthorityWithOffset); + vm.expectRevert("error"); + receiver.forward(abi.encodeCall(TargetContractMock.revertFunc, ())); + } + +} From dc07c16bf3da0a39c61b77568492559628cf015f Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Wed, 5 Jun 2024 19:35:53 +0900 Subject: [PATCH 05/10] add optimism test --- test/OptimismReceiver.t.sol | 84 +++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/OptimismReceiver.t.sol diff --git a/test/OptimismReceiver.t.sol b/test/OptimismReceiver.t.sol new file mode 100644 index 0000000..0fdb387 --- /dev/null +++ b/test/OptimismReceiver.t.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; + +import { TargetContractMock } from "test/mocks/TargetContractMock.sol"; + +import { OptimismReceiver } from "src/receivers/OptimismReceiver.sol"; + +contract OptimismMessengerMock { + + address public xDomainMessageSender; + + function __setSender(address _xDomainMessageSender) public { + xDomainMessageSender = _xDomainMessageSender; + } + +} + +contract OptimismReceiverTest is Test { + + OptimismMessengerMock l2CrossDomain; + TargetContractMock target; + + OptimismReceiver receiver; + + address l2CrossDomainAddr = 0x4200000000000000000000000000000000000007; + + address sourceAuthority = makeAddr("sourceAuthority"); + address randomAddress = makeAddr("randomAddress"); + + function setUp() public { + // Set the code at the particular address + l2CrossDomain = new OptimismMessengerMock(); + vm.etch(l2CrossDomainAddr, address(l2CrossDomain).code); + l2CrossDomain = OptimismMessengerMock(l2CrossDomainAddr); + l2CrossDomain.__setSender(sourceAuthority); + + target = new TargetContractMock(); + + receiver = new OptimismReceiver( + sourceAuthority, + address(target) + ); + } + + function test_constructor() public { + receiver = new OptimismReceiver( + sourceAuthority, + address(target) + ); + + assertEq(receiver.l1Authority(), sourceAuthority); + assertEq(receiver.target(), address(target)); + } + + function test_forward_invalidSender() public { + vm.prank(randomAddress); + vm.expectRevert("OptimismReceiver/invalid-sender"); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + } + + function test_forward_invalidL1Authority() public { + l2CrossDomain.__setSender(randomAddress); + + vm.prank(address(l2CrossDomain)); + vm.expectRevert("OptimismReceiver/invalid-l1Authority"); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + } + + function test_forward_success() public { + assertEq(target.data(), 0); + vm.prank(address(l2CrossDomain)); + receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + assertEq(target.data(), 1); + } + + function test_forward_revert() public { + vm.prank(address(l2CrossDomain)); + vm.expectRevert("error"); + receiver.forward(abi.encodeCall(TargetContractMock.revertFunc, ())); + } + +} From 9874e5c5a158f8cb33457363ba0c77219e4456d6 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Sat, 8 Jun 2024 19:52:33 +0900 Subject: [PATCH 06/10] use relative paths for library code --- src/testing/bridges/AMBBridgeTesting.sol | 6 +++--- src/testing/bridges/ArbitrumBridgeTesting.sol | 6 +++--- src/testing/bridges/CCTPBridgeTesting.sol | 6 +++--- src/testing/bridges/OptimismBridgeTesting.sol | 6 +++--- src/testing/utils/RecordedLogs.sol | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/testing/bridges/AMBBridgeTesting.sol b/src/testing/bridges/AMBBridgeTesting.sol index e1b28c6..32c3cec 100644 --- a/src/testing/bridges/AMBBridgeTesting.sol +++ b/src/testing/bridges/AMBBridgeTesting.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.0; import { Vm } from "forge-std/Vm.sol"; -import { Bridge } from "src/testing/Bridge.sol"; -import { Domain, DomainHelpers } from "src/testing/Domain.sol"; -import { RecordedLogs } from "src/testing/utils/RecordedLogs.sol"; +import { Bridge } from "../Bridge.sol"; +import { Domain, DomainHelpers } from "../Domain.sol"; +import { RecordedLogs } from "../utils/RecordedLogs.sol"; interface IAMB { function validatorContract() external view returns (address); diff --git a/src/testing/bridges/ArbitrumBridgeTesting.sol b/src/testing/bridges/ArbitrumBridgeTesting.sol index 073d40e..0046b88 100644 --- a/src/testing/bridges/ArbitrumBridgeTesting.sol +++ b/src/testing/bridges/ArbitrumBridgeTesting.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.0; import { Vm } from "forge-std/Vm.sol"; -import { Bridge } from "src/testing/Bridge.sol"; -import { Domain, DomainHelpers } from "src/testing/Domain.sol"; -import { RecordedLogs } from "src/testing/utils/RecordedLogs.sol"; +import { Bridge } from "../Bridge.sol"; +import { Domain, DomainHelpers } from "../Domain.sol"; +import { RecordedLogs } from "../utils/RecordedLogs.sol"; interface InboxLike { function createRetryableTicket( diff --git a/src/testing/bridges/CCTPBridgeTesting.sol b/src/testing/bridges/CCTPBridgeTesting.sol index 229a2b2..bc91f6d 100644 --- a/src/testing/bridges/CCTPBridgeTesting.sol +++ b/src/testing/bridges/CCTPBridgeTesting.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.0; import { Vm } from "forge-std/Vm.sol"; -import { Bridge } from "src/testing/Bridge.sol"; -import { Domain, DomainHelpers } from "src/testing/Domain.sol"; -import { RecordedLogs } from "src/testing/utils/RecordedLogs.sol"; +import { Bridge } from "../Bridge.sol"; +import { Domain, DomainHelpers } from "../Domain.sol"; +import { RecordedLogs } from "../utils/RecordedLogs.sol"; interface IMessenger { function receiveMessage(bytes calldata message, bytes calldata attestation) external returns (bool success); diff --git a/src/testing/bridges/OptimismBridgeTesting.sol b/src/testing/bridges/OptimismBridgeTesting.sol index 97626a5..4e3fbee 100644 --- a/src/testing/bridges/OptimismBridgeTesting.sol +++ b/src/testing/bridges/OptimismBridgeTesting.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.0; import { Vm } from "forge-std/Vm.sol"; -import { Bridge } from "src/testing/Bridge.sol"; -import { Domain, DomainHelpers } from "src/testing/Domain.sol"; -import { RecordedLogs } from "src/testing/utils/RecordedLogs.sol"; +import { Bridge } from "../Bridge.sol"; +import { Domain, DomainHelpers } from "../Domain.sol"; +import { RecordedLogs } from "../utils/RecordedLogs.sol"; interface IMessenger { function sendMessage( diff --git a/src/testing/utils/RecordedLogs.sol b/src/testing/utils/RecordedLogs.sol index 4912a24..0658f33 100644 --- a/src/testing/utils/RecordedLogs.sol +++ b/src/testing/utils/RecordedLogs.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.0; import { Vm } from "forge-std/Vm.sol"; -import { Bridge } from "src/testing/Bridge.sol"; +import { Bridge } from "../Bridge.sol"; library RecordedLogs { From 46ee62c4ec1f2abf51842c952c13b142704fcfc1 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Sat, 8 Jun 2024 20:23:21 +0900 Subject: [PATCH 07/10] fix for subsequent messages --- src/testing/bridges/AMBBridgeTesting.sol | 4 ++-- src/testing/bridges/ArbitrumBridgeTesting.sol | 4 ++-- src/testing/bridges/CCTPBridgeTesting.sol | 4 ++-- src/testing/bridges/OptimismBridgeTesting.sol | 4 ++-- src/testing/utils/RecordedLogs.sol | 4 ++-- test/IntegrationBase.t.sol | 10 ++++++++++ 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/testing/bridges/AMBBridgeTesting.sol b/src/testing/bridges/AMBBridgeTesting.sol index 32c3cec..0340e7d 100644 --- a/src/testing/bridges/AMBBridgeTesting.sol +++ b/src/testing/bridges/AMBBridgeTesting.sol @@ -71,7 +71,7 @@ library AMBBridgeTesting { return bridge; } - function relayMessagesToDestination(Bridge memory bridge, bool switchToDestinationFork) internal { + function relayMessagesToDestination(Bridge storage bridge, bool switchToDestinationFork) internal { bridge.destination.selectFork(); Vm.Log[] memory logs = bridge.ingestAndFilterLogs(true, USER_REQUEST_FOR_AFFIRMATION_TOPIC, USER_REQUEST_FOR_SIGNATURE_TOPIC, bridge.sourceCrossChainMessenger); @@ -82,7 +82,7 @@ library AMBBridgeTesting { } } - function relayMessagesToSource(Bridge memory bridge, bool switchToSourceFork) internal { + function relayMessagesToSource(Bridge storage bridge, bool switchToSourceFork) internal { bridge.source.selectFork(); Vm.Log[] memory logs = bridge.ingestAndFilterLogs(false, USER_REQUEST_FOR_AFFIRMATION_TOPIC, USER_REQUEST_FOR_SIGNATURE_TOPIC, bridge.destinationCrossChainMessenger); diff --git a/src/testing/bridges/ArbitrumBridgeTesting.sol b/src/testing/bridges/ArbitrumBridgeTesting.sol index 0046b88..4ab8ece 100644 --- a/src/testing/bridges/ArbitrumBridgeTesting.sol +++ b/src/testing/bridges/ArbitrumBridgeTesting.sol @@ -122,7 +122,7 @@ library ArbitrumBridgeTesting { return bridge; } - function relayMessagesToDestination(Bridge memory bridge, bool switchToDestinationFork) internal { + function relayMessagesToDestination(Bridge storage bridge, bool switchToDestinationFork) internal { bridge.destination.selectFork(); Vm.Log[] memory logs = RecordedLogs.getLogs(); @@ -149,7 +149,7 @@ library ArbitrumBridgeTesting { } } - function relayMessagesToSource(Bridge memory bridge, bool switchToSourceFork) internal { + function relayMessagesToSource(Bridge storage bridge, bool switchToSourceFork) internal { bridge.source.selectFork(); Vm.Log[] memory logs = bridge.ingestAndFilterLogs(false, SEND_TO_L1_TOPIC, bridge.destinationCrossChainMessenger); diff --git a/src/testing/bridges/CCTPBridgeTesting.sol b/src/testing/bridges/CCTPBridgeTesting.sol index bc91f6d..5a90714 100644 --- a/src/testing/bridges/CCTPBridgeTesting.sol +++ b/src/testing/bridges/CCTPBridgeTesting.sol @@ -71,7 +71,7 @@ library CCTPBridgeTesting { return bridge; } - function relayMessagesToDestination(Bridge memory bridge, bool switchToDestinationFork) internal { + function relayMessagesToDestination(Bridge storage bridge, bool switchToDestinationFork) internal { bridge.destination.selectFork(); Vm.Log[] memory logs = bridge.ingestAndFilterLogs(true, SENT_MESSAGE_TOPIC, bridge.sourceCrossChainMessenger); @@ -84,7 +84,7 @@ library CCTPBridgeTesting { } } - function relayMessagesToSource(Bridge memory bridge, bool switchToSourceFork) internal { + function relayMessagesToSource(Bridge storage bridge, bool switchToSourceFork) internal { bridge.source.selectFork(); Vm.Log[] memory logs = bridge.ingestAndFilterLogs(false, SENT_MESSAGE_TOPIC, bridge.destinationCrossChainMessenger); diff --git a/src/testing/bridges/OptimismBridgeTesting.sol b/src/testing/bridges/OptimismBridgeTesting.sol index 4e3fbee..7823e6f 100644 --- a/src/testing/bridges/OptimismBridgeTesting.sol +++ b/src/testing/bridges/OptimismBridgeTesting.sol @@ -78,7 +78,7 @@ library OptimismBridgeTesting { return bridge; } - function relayMessagesToDestination(Bridge memory bridge, bool switchToDestinationFork) internal { + function relayMessagesToDestination(Bridge storage bridge, bool switchToDestinationFork) internal { bridge.destination.selectFork(); address malias; @@ -100,7 +100,7 @@ library OptimismBridgeTesting { } } - function relayMessagesToSource(Bridge memory bridge, bool switchToSourceFork) internal { + function relayMessagesToSource(Bridge storage bridge, bool switchToSourceFork) internal { bridge.source.selectFork(); Vm.Log[] memory logs = bridge.ingestAndFilterLogs(false, SENT_MESSAGE_TOPIC, bridge.destinationCrossChainMessenger); diff --git a/src/testing/utils/RecordedLogs.sol b/src/testing/utils/RecordedLogs.sol index 0658f33..1ff477d 100644 --- a/src/testing/utils/RecordedLogs.sol +++ b/src/testing/utils/RecordedLogs.sol @@ -33,7 +33,7 @@ library RecordedLogs { return logs; } - function ingestAndFilterLogs(Bridge memory bridge, bool sourceToDestination, bytes32 topic0, bytes32 topic1, address emitter) internal returns (Vm.Log[] memory filteredLogs) { + function ingestAndFilterLogs(Bridge storage bridge, bool sourceToDestination, bytes32 topic0, bytes32 topic1, address emitter) internal returns (Vm.Log[] memory filteredLogs) { Vm.Log[] memory logs = RecordedLogs.getLogs(); uint256 lastIndex = sourceToDestination ? bridge.lastSourceLogIndex : bridge.lastDestinationLogIndex; uint256 pushedIndex = 0; @@ -53,7 +53,7 @@ library RecordedLogs { assembly { mstore(filteredLogs, pushedIndex) } } - function ingestAndFilterLogs(Bridge memory bridge, bool sourceToDestination, bytes32 topic, address emitter) internal returns (Vm.Log[] memory filteredLogs) { + function ingestAndFilterLogs(Bridge storage bridge, bool sourceToDestination, bytes32 topic, address emitter) internal returns (Vm.Log[] memory filteredLogs) { return ingestAndFilterLogs(bridge, sourceToDestination, topic, bytes32(0), emitter); } diff --git a/test/IntegrationBase.t.sol b/test/IntegrationBase.t.sol index 2f40cc9..aa16544 100644 --- a/test/IntegrationBase.t.sol +++ b/test/IntegrationBase.t.sol @@ -105,6 +105,16 @@ abstract contract IntegrationBaseTest is Test { assertEq(moSource.length(), 2); assertEq(moSource.messages(0), 3); assertEq(moSource.messages(1), 4); + + // One more message to destination + vm.startPrank(sourceAuthority); + queueSourceToDestination(abi.encodeCall(MessageOrdering.push, (5))); + vm.stopPrank(); + + relaySourceToDestination(); + + assertEq(moDestination.length(), 3); + assertEq(moDestination.messages(2), 5); } function initSourceReceiver() internal virtual returns (address); From 6be2397aa4f6e9465a763f609e25a9111ffff200 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Sun, 9 Jun 2024 17:54:49 +0900 Subject: [PATCH 08/10] fix tests to remove forward() --- test/AMBReceiver.t.sol | 10 +++++----- test/ArbitrumReceiver.t.sol | 8 ++++---- test/OptimismReceiver.t.sol | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test/AMBReceiver.t.sol b/test/AMBReceiver.t.sol index b1b5986..689e218 100644 --- a/test/AMBReceiver.t.sol +++ b/test/AMBReceiver.t.sol @@ -67,7 +67,7 @@ contract AMBReceiverTest is Test { function test_forward_invalidSender() public { vm.prank(randomAddress); vm.expectRevert("AMBReceiver/invalid-sender"); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); } function test_forward_invalidSourceChainId() public { @@ -75,7 +75,7 @@ contract AMBReceiverTest is Test { vm.prank(address(amb)); vm.expectRevert("AMBReceiver/invalid-sourceChainId"); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); } function test_forward_invalidSourceAuthority() public { @@ -83,20 +83,20 @@ contract AMBReceiverTest is Test { vm.prank(address(amb)); vm.expectRevert("AMBReceiver/invalid-sourceAuthority"); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); } function test_forward_success() public { assertEq(target.data(), 0); vm.prank(address(amb)); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); assertEq(target.data(), 1); } function test_forward_revert() public { vm.prank(address(amb)); vm.expectRevert("error"); - receiver.forward(abi.encodeCall(TargetContractMock.revertFunc, ())); + TargetContractMock(address(receiver)).revertFunc(); } } diff --git a/test/ArbitrumReceiver.t.sol b/test/ArbitrumReceiver.t.sol index 02d57c6..c205420 100644 --- a/test/ArbitrumReceiver.t.sol +++ b/test/ArbitrumReceiver.t.sol @@ -42,26 +42,26 @@ contract ArbitrumReceiverTest is Test { function test_forward_invalidL1Authority() public { vm.prank(randomAddress); vm.expectRevert("ArbitrumReceiver/invalid-l1Authority"); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); } function test_forward_invalidL1AuthoritySourceAuthorityNoOffset() public { vm.prank(sourceAuthority); vm.expectRevert("ArbitrumReceiver/invalid-l1Authority"); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); } function test_forward_success() public { assertEq(target.data(), 0); vm.prank(sourceAuthorityWithOffset); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); assertEq(target.data(), 1); } function test_forward_revert() public { vm.prank(sourceAuthorityWithOffset); vm.expectRevert("error"); - receiver.forward(abi.encodeCall(TargetContractMock.revertFunc, ())); + TargetContractMock(address(receiver)).revertFunc(); } } diff --git a/test/OptimismReceiver.t.sol b/test/OptimismReceiver.t.sol index 0fdb387..85be4c7 100644 --- a/test/OptimismReceiver.t.sol +++ b/test/OptimismReceiver.t.sol @@ -57,7 +57,7 @@ contract OptimismReceiverTest is Test { function test_forward_invalidSender() public { vm.prank(randomAddress); vm.expectRevert("OptimismReceiver/invalid-sender"); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); } function test_forward_invalidL1Authority() public { @@ -65,20 +65,20 @@ contract OptimismReceiverTest is Test { vm.prank(address(l2CrossDomain)); vm.expectRevert("OptimismReceiver/invalid-l1Authority"); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); } function test_forward_success() public { assertEq(target.data(), 0); vm.prank(address(l2CrossDomain)); - receiver.forward(abi.encodeCall(TargetContractMock.someFunc, ())); + TargetContractMock(address(receiver)).someFunc(); assertEq(target.data(), 1); } function test_forward_revert() public { vm.prank(address(l2CrossDomain)); vm.expectRevert("error"); - receiver.forward(abi.encodeCall(TargetContractMock.revertFunc, ())); + TargetContractMock(address(receiver)).revertFunc(); } } From 0c2893daddc98cb8c10bd50d287e6bbe7cbf2ea0 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Wed, 12 Jun 2024 19:14:47 +0900 Subject: [PATCH 09/10] review fixes --- test/AMBReceiver.t.sol | 14 +++++++------- test/ArbitrumReceiver.t.sol | 12 ++++++------ test/CCTPReceiver.t.sol | 17 +++++++++-------- test/IntegrationBase.t.sol | 11 ++++++++++- test/OptimismReceiver.t.sol | 12 ++++++------ test/mocks/TargetContractMock.sol | 8 ++++---- 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/test/AMBReceiver.t.sol b/test/AMBReceiver.t.sol index 689e218..322ef6b 100644 --- a/test/AMBReceiver.t.sol +++ b/test/AMBReceiver.t.sol @@ -67,7 +67,7 @@ contract AMBReceiverTest is Test { function test_forward_invalidSender() public { vm.prank(randomAddress); vm.expectRevert("AMBReceiver/invalid-sender"); - TargetContractMock(address(receiver)).someFunc(); + TargetContractMock(address(receiver)).increment(); } function test_forward_invalidSourceChainId() public { @@ -75,7 +75,7 @@ contract AMBReceiverTest is Test { vm.prank(address(amb)); vm.expectRevert("AMBReceiver/invalid-sourceChainId"); - TargetContractMock(address(receiver)).someFunc(); + TargetContractMock(address(receiver)).increment(); } function test_forward_invalidSourceAuthority() public { @@ -83,19 +83,19 @@ contract AMBReceiverTest is Test { vm.prank(address(amb)); vm.expectRevert("AMBReceiver/invalid-sourceAuthority"); - TargetContractMock(address(receiver)).someFunc(); + TargetContractMock(address(receiver)).increment(); } function test_forward_success() public { - assertEq(target.data(), 0); + assertEq(target.count(), 0); vm.prank(address(amb)); - TargetContractMock(address(receiver)).someFunc(); - assertEq(target.data(), 1); + TargetContractMock(address(receiver)).increment(); + assertEq(target.count(), 1); } function test_forward_revert() public { vm.prank(address(amb)); - vm.expectRevert("error"); + vm.expectRevert("TargetContract/error"); TargetContractMock(address(receiver)).revertFunc(); } diff --git a/test/ArbitrumReceiver.t.sol b/test/ArbitrumReceiver.t.sol index c205420..7ae6bf3 100644 --- a/test/ArbitrumReceiver.t.sol +++ b/test/ArbitrumReceiver.t.sol @@ -42,25 +42,25 @@ contract ArbitrumReceiverTest is Test { function test_forward_invalidL1Authority() public { vm.prank(randomAddress); vm.expectRevert("ArbitrumReceiver/invalid-l1Authority"); - TargetContractMock(address(receiver)).someFunc(); + TargetContractMock(address(receiver)).increment(); } function test_forward_invalidL1AuthoritySourceAuthorityNoOffset() public { vm.prank(sourceAuthority); vm.expectRevert("ArbitrumReceiver/invalid-l1Authority"); - TargetContractMock(address(receiver)).someFunc(); + TargetContractMock(address(receiver)).increment(); } function test_forward_success() public { - assertEq(target.data(), 0); + assertEq(target.count(), 0); vm.prank(sourceAuthorityWithOffset); - TargetContractMock(address(receiver)).someFunc(); - assertEq(target.data(), 1); + TargetContractMock(address(receiver)).increment(); + assertEq(target.count(), 1); } function test_forward_revert() public { vm.prank(sourceAuthorityWithOffset); - vm.expectRevert("error"); + vm.expectRevert("TargetContract/error"); TargetContractMock(address(receiver)).revertFunc(); } diff --git a/test/CCTPReceiver.t.sol b/test/CCTPReceiver.t.sol index 4f77c04..00b6c74 100644 --- a/test/CCTPReceiver.t.sol +++ b/test/CCTPReceiver.t.sol @@ -49,7 +49,7 @@ contract CCTPReceiverTest is Test { receiver.handleReceiveMessage( sourceDomainId, sourceAuthority, - abi.encodeCall(TargetContractMock.someFunc, ()) + abi.encodeCall(TargetContractMock.increment, ()) ); } @@ -59,7 +59,7 @@ contract CCTPReceiverTest is Test { receiver.handleReceiveMessage( 2, sourceAuthority, - abi.encodeCall(TargetContractMock.someFunc, ()) + abi.encodeCall(TargetContractMock.increment, ()) ); } @@ -69,24 +69,25 @@ contract CCTPReceiverTest is Test { receiver.handleReceiveMessage( sourceDomainId, bytes32(uint256(uint160(randomAddress))), - abi.encodeCall(TargetContractMock.someFunc, ()) + abi.encodeCall(TargetContractMock.increment, ()) ); } function test_handleReceiveMessage_success() public { - assertEq(target.data(), 0); + assertEq(target.count(), 0); vm.prank(destinationMessenger); - receiver.handleReceiveMessage( + bool result = receiver.handleReceiveMessage( sourceDomainId, sourceAuthority, - abi.encodeCall(TargetContractMock.someFunc, ()) + abi.encodeCall(TargetContractMock.increment, ()) ); - assertEq(target.data(), 1); + assertEq(result, true); + assertEq(target.count(), 1); } function test_handleReceiveMessage_revert() public { vm.prank(destinationMessenger); - vm.expectRevert("error"); + vm.expectRevert("TargetContract/error"); receiver.handleReceiveMessage( sourceDomainId, sourceAuthority, diff --git a/test/IntegrationBase.t.sol b/test/IntegrationBase.t.sol index aa16544..b81f644 100644 --- a/test/IntegrationBase.t.sol +++ b/test/IntegrationBase.t.sol @@ -106,7 +106,7 @@ abstract contract IntegrationBaseTest is Test { assertEq(moSource.messages(0), 3); assertEq(moSource.messages(1), 4); - // One more message to destination + // Do one more message both ways to ensure subsequent calls don't repeat already sent messages vm.startPrank(sourceAuthority); queueSourceToDestination(abi.encodeCall(MessageOrdering.push, (5))); vm.stopPrank(); @@ -115,6 +115,15 @@ abstract contract IntegrationBaseTest is Test { assertEq(moDestination.length(), 3); assertEq(moDestination.messages(2), 5); + + vm.startPrank(destinationAuthority); + queueDestinationToSource(abi.encodeCall(MessageOrdering.push, (6))); + vm.stopPrank(); + + relayDestinationToSource(); + + assertEq(moSource.length(), 3); + assertEq(moSource.messages(2), 6); } function initSourceReceiver() internal virtual returns (address); diff --git a/test/OptimismReceiver.t.sol b/test/OptimismReceiver.t.sol index 85be4c7..85d18a1 100644 --- a/test/OptimismReceiver.t.sol +++ b/test/OptimismReceiver.t.sol @@ -57,7 +57,7 @@ contract OptimismReceiverTest is Test { function test_forward_invalidSender() public { vm.prank(randomAddress); vm.expectRevert("OptimismReceiver/invalid-sender"); - TargetContractMock(address(receiver)).someFunc(); + TargetContractMock(address(receiver)).increment(); } function test_forward_invalidL1Authority() public { @@ -65,19 +65,19 @@ contract OptimismReceiverTest is Test { vm.prank(address(l2CrossDomain)); vm.expectRevert("OptimismReceiver/invalid-l1Authority"); - TargetContractMock(address(receiver)).someFunc(); + TargetContractMock(address(receiver)).increment(); } function test_forward_success() public { - assertEq(target.data(), 0); + assertEq(target.count(), 0); vm.prank(address(l2CrossDomain)); - TargetContractMock(address(receiver)).someFunc(); - assertEq(target.data(), 1); + TargetContractMock(address(receiver)).increment(); + assertEq(target.count(), 1); } function test_forward_revert() public { vm.prank(address(l2CrossDomain)); - vm.expectRevert("error"); + vm.expectRevert("TargetContract/error"); TargetContractMock(address(receiver)).revertFunc(); } diff --git a/test/mocks/TargetContractMock.sol b/test/mocks/TargetContractMock.sol index 77fddb0..47c3052 100644 --- a/test/mocks/TargetContractMock.sol +++ b/test/mocks/TargetContractMock.sol @@ -3,14 +3,14 @@ pragma solidity >=0.8.0; contract TargetContractMock { - uint256 public data; + uint256 public count; - function someFunc() external { - data++; + function increment() external { + count++; } function revertFunc() external pure { - revert("error"); + revert("TargetContract/error"); } } From fd8a5f825259c15f47a4ddb5e383c4aca2f1789e Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Thu, 13 Jun 2024 00:36:18 +0900 Subject: [PATCH 10/10] align --- test/CCTPReceiver.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CCTPReceiver.t.sol b/test/CCTPReceiver.t.sol index 00b6c74..7ad684f 100644 --- a/test/CCTPReceiver.t.sol +++ b/test/CCTPReceiver.t.sol @@ -81,7 +81,7 @@ contract CCTPReceiverTest is Test { sourceAuthority, abi.encodeCall(TargetContractMock.increment, ()) ); - assertEq(result, true); + assertEq(result, true); assertEq(target.count(), 1); }