-
Notifications
You must be signed in to change notification settings - Fork 10
Test MessageRelayer #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nikeshnazareth
wants to merge
34
commits into
main
Choose a base branch
from
tests/message-relayer
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Test MessageRelayer #142
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
b8d8acd
Create initial state
nikeshnazareth a60d464
Create default message
nikeshnazareth d2aed97
Create message recipient
nikeshnazareth 6b84dba
Create DepositRecipientScenarios
nikeshnazareth 6205519
Create TipRecipientScenarios
nikeshnazareth c67ec39
Test claimDeposit path
nikeshnazareth 9074f4d
add more scenarios
LeoPatOZ fa42d46
made scripts easier to work with
LeoPatOZ cc68261
reentrancy test
LeoPatOZ f0ee2db
remove uneeded counter
LeoPatOZ ffd4e33
fix scenarios
LeoPatOZ ac4471c
add more test scenarios
LeoPatOZ a3de214
better testing scenario
LeoPatOZ bd61c84
transient storage test
LeoPatOZ 443b9e2
Merge branch 'main' into tests/message-relayer
LeoPatOZ f781997
update scenario
LeoPatOZ 5347332
name
LeoPatOZ 521fd25
Merge branch 'main' into tests/message-relayer
LeoPatOZ 4608dc8
Create ifTxSucceeds modifier
nikeshnazareth 28fb7bd
Remove InitialStateTest
nikeshnazareth d093a79
Use ifTxSucceeds so UserSetInvalidTipRecipient can inherit DepositRec…
nikeshnazareth 0800551
Expand TipRecipientScenarios using the ifRelaySucceeds mechanism
nikeshnazareth 0b1c6e7
Move shouldRevert checks to the InitialState contract
nikeshnazareth 3b60423
Migrate FundAmountScenarios to the new structure
nikeshnazareth df1457e
Remove unused TIP_RECIPIENT_SLOT
nikeshnazareth 9fb7b06
Test GasLimitScenarios
nikeshnazareth a0fed52
Migrate RelayRecipientScenarios to new structure
nikeshnazareth 240c6d9
Create default scenarios for better encapsulation
nikeshnazareth 4794e23
Fix InsufficientValue comment
nikeshnazareth 7e30320
Run forge fmt
nikeshnazareth bac25c5
Increase OOG_INSIDE_RECIPIENT
nikeshnazareth d77e2ae
typo
LeoPatOZ 0c38142
Merge branch 'main' into tests/message-relayer
nikeshnazareth 9ff57d2
Set signalService to verify all signals
nikeshnazareth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| import {GenericRecipient} from "./GenericRecipient.t.sol"; | ||
| import {InitialState} from "./InitialState.t.sol"; | ||
|
|
||
| import {IETHBridge} from "src/protocol/IETHBridge.sol"; | ||
| import {IMessageRelayer} from "src/protocol/IMessageRelayer.sol"; | ||
|
|
||
| abstract contract DepositRecipientScenarios is InitialState {} | ||
|
|
||
| contract DepositRecipientIsMessageRelayer is DepositRecipientScenarios { | ||
| function test_DepositRecipientIsMessageRelayer_relayMessage_shouldInvokeReceiveMessage() public ifRelaySucceeds { | ||
| vm.expectCall(address(messageRelayer), ethDeposit.data); | ||
| _relayMessage(); | ||
| } | ||
|
|
||
| function test_DepositRecipientIsMessageRelayer_claimDeposit_shouldInvokeReceiveMessage() public ifClaimSucceeds { | ||
| vm.expectCall(address(messageRelayer), ethDeposit.data); | ||
| _claimDeposit(); | ||
| } | ||
| } | ||
|
|
||
| contract DepositRecipientIsNotMessageRelayer is DepositRecipientScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| // bypass the relayer and send the message directly to the recipient | ||
| // do not bother changing the default message encoding (to a `receiveMessage` function) | ||
| // because the recipient handles any message | ||
| ethDeposit.to = address(to); | ||
| } | ||
|
|
||
| function test_DepositRecipientIsNotMessageRelayer_relayMessage_shouldInvokeRecipient() public { | ||
| vm.expectEmit(); | ||
| emit GenericRecipient.FunctionCalled(); | ||
| _relayMessage(); | ||
| } | ||
|
|
||
| function test_DepositRecipientIsNotMessageRelayer_relayMessage_shouldNotInvokeReceiveMessage() public { | ||
| vm.expectCall(address(messageRelayer), ethDeposit.data, 0); | ||
| _relayMessage(); | ||
| } | ||
| } | ||
|
|
||
| // A valid scenario that can be used as a default scenario by unrelated tests. | ||
| abstract contract DefaultRecipientScenario is DepositRecipientScenarios {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| import {GenericRecipient} from "./GenericRecipient.t.sol"; | ||
| import {DefaultTipRecipientScenario} from "./TipRecipientScenarios.t.sol"; | ||
| import {IMessageRelayer} from "src/protocol/IMessageRelayer.sol"; | ||
|
|
||
| import {InitialState} from "./InitialState.t.sol"; | ||
| import {IETHBridge} from "src/protocol/IETHBridge.sol"; | ||
|
|
||
| abstract contract FundAmountScenarios is DefaultTipRecipientScenario { | ||
| function test_FundAmountScenarios_relayMessage_shouldInvokeRecipient() public ifRelaySucceeds { | ||
| vm.expectEmit(); | ||
| emit GenericRecipient.FunctionCalled(); | ||
| _relayMessage(); | ||
| } | ||
|
|
||
| function test_FundAmountScenarios_relayMessage_shouldNotRetainFundsInRelayer() public ifRelaySucceeds { | ||
| assertEq(address(messageRelayer).balance, 0, "relayer should not have funds"); | ||
| _relayMessage(); | ||
| assertEq(address(messageRelayer).balance, 0, "relayer should not retain funds"); | ||
| } | ||
|
|
||
| function test_FundAmountScenarios_relayMessage_shouldSendAmountToRecipient() public ifRelaySucceeds { | ||
| uint256 balanceBefore = address(to).balance; | ||
| uint256 transferAmount = ethDeposit.amount - tip; | ||
| _relayMessage(); | ||
| assertEq(address(to).balance, balanceBefore + transferAmount, "recipient balance mismatch"); | ||
| } | ||
|
|
||
| function redundant_FundAmountScenarios_relayMessage_shouldSendTipToRecipient() public { | ||
| // This test (if it were implemented) would be redundant with the tip recipient scenarios | ||
| // It is included for completeness, so this file accounts for all the distributed funds | ||
| } | ||
| } | ||
|
|
||
| contract AmountExceedsTip is FundAmountScenarios {} | ||
|
|
||
| contract NoAmountNoTip is FundAmountScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| ethDeposit.amount = 0; | ||
| tip = 0; | ||
| _encodeReceiveCall(); | ||
| } | ||
| } | ||
|
|
||
| contract NoAmountNonzeroTip is FundAmountScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| ethDeposit.amount = 0; | ||
| relayShouldSucceed = false; | ||
| claimShouldSucceed = false; | ||
| } | ||
| } | ||
|
|
||
| contract AmountLessThanTip is FundAmountScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| ethDeposit.amount = tip - 1 wei; | ||
| relayShouldSucceed = false; | ||
| claimShouldSucceed = false; | ||
| } | ||
| } | ||
|
|
||
| // A valid scenario that can be used as a default scenario by unrelated tests. | ||
| abstract contract DefaultFundAmountScenario is AmountExceedsTip {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| import {DefaultFundAmountScenario} from "./FundAmountScenarios.t.sol"; | ||
| import {GenericRecipient} from "./GenericRecipient.t.sol"; | ||
|
|
||
| import {InitialState} from "./InitialState.t.sol"; | ||
| import {IETHBridge} from "src/protocol/IETHBridge.sol"; | ||
| import {IMessageRelayer} from "src/protocol/IMessageRelayer.sol"; | ||
|
|
||
| // Found by experimentation | ||
| uint256 constant OOG_INSIDE_RECIPIENT = 70_000; | ||
|
|
||
| abstract contract GasLimitScenarios is DefaultFundAmountScenario {} | ||
|
|
||
| contract NoGasLimit_SufficientGasProvided is GasLimitScenarios {} | ||
|
|
||
| contract NoGasLimit_InsufficientGasProvided is GasLimitScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| gasProvidedWithCall = OOG_INSIDE_RECIPIENT; | ||
| relayShouldSucceed = false; | ||
| claimShouldSucceed = false; | ||
| } | ||
| } | ||
|
|
||
| contract SufficientGasLimit_SufficientGasProvided is GasLimitScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| gasLimit = to.GAS_REQUIRED() + 100; | ||
| _encodeReceiveCall(); | ||
| } | ||
| } | ||
|
|
||
| contract SufficientGasLimit_InsufficientGasProvided is GasLimitScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| gasLimit = to.GAS_REQUIRED() + 100; | ||
| _encodeReceiveCall(); | ||
| gasProvidedWithCall = OOG_INSIDE_RECIPIENT; | ||
| relayShouldSucceed = false; | ||
| claimShouldSucceed = false; | ||
| } | ||
| } | ||
|
|
||
| contract InsufficientGasLimit_SufficientGasProvided is GasLimitScenarios { | ||
| function setUp() public override { | ||
| super.setUp(); | ||
| // the amount forwarded to the recipient is slightly higher than gasLimit so deduct 150 as compensation | ||
| // TODO: understand why this is necessary | ||
| gasLimit = to.GAS_REQUIRED() - 150; | ||
| _encodeReceiveCall(); | ||
| relayShouldSucceed = false; | ||
| claimShouldSucceed = false; | ||
| } | ||
| } | ||
|
|
||
| // A valid scenario that can be used as a default scenario by unrelated tests. | ||
| abstract contract DefaultGasLimitScenario is NoGasLimit_SufficientGasProvided {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| import {IMessageRelayer} from "src/protocol/IMessageRelayer.sol"; | ||
|
|
||
| interface IGenericRecipient { | ||
| function setSuccess(bool _callWillSucceed) external; | ||
| function setReentrancyAttack(bool _shouldAttack) external; | ||
| } | ||
|
|
||
| contract GenericRecipient is IGenericRecipient { | ||
| bool private callWillSucceed = true; | ||
| bool private shouldReenterAttack = false; | ||
| address private relayer; | ||
|
|
||
| // Consume a minimum amount of gas so we can test gas limits | ||
| uint256 public constant GAS_REQUIRED = 20_000; | ||
|
|
||
| error CallFailed(); | ||
|
|
||
| event FunctionCalled(); | ||
|
|
||
| constructor(address _relayer) { | ||
| relayer = _relayer; | ||
| } | ||
|
|
||
| function setSuccess(bool _callWillSucceed) external { | ||
| callWillSucceed = _callWillSucceed; | ||
| } | ||
|
|
||
| function setReentrancyAttack(bool _shouldAttack) external { | ||
| shouldReenterAttack = _shouldAttack; | ||
| } | ||
|
|
||
| fallback() external payable { | ||
| _simulateFunctionCall(); | ||
| } | ||
|
|
||
| receive() external payable { | ||
| _simulateFunctionCall(); | ||
| } | ||
|
|
||
| function _simulateFunctionCall() internal { | ||
| require(callWillSucceed, CallFailed()); | ||
| require(gasleft() >= GAS_REQUIRED, "Insufficient gas"); | ||
|
|
||
| emit FunctionCalled(); | ||
|
|
||
| if (shouldReenterAttack) { | ||
| IMessageRelayer(relayer).receiveMessage(address(this), 0, address(this), 0, "0x"); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix syntax error in require statement.
The
requirestatement with a custom error is using incorrect syntax. Therequirefunction expects a string message, not a custom error.Apply this diff to fix the syntax error:
function _simulateFunctionCall() internal { - require(callWillSucceed, CallFailed()); + if (!callWillSucceed) { + revert CallFailed(); + } emit FunctionCalled(); }📝 Committable suggestion
🤖 Prompt for AI Agents