Skip to content

Commit cc68261

Browse files
committed
reentrancy test
1 parent fa42d46 commit cc68261

File tree

5 files changed

+66
-5
lines changed

5 files changed

+66
-5
lines changed

test/MessageRelayer/DepositRecipientScenarios.t.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ pragma solidity ^0.8.28;
33

44
import {GenericRecipient} from "./GenericRecipient.t.sol";
55
import {InitialState} from "./InitialState.t.sol";
6+
7+
import {IETHBridge} from "src/protocol/IETHBridge.sol";
68
import {IMessageRelayer} from "src/protocol/IMessageRelayer.sol";
79

810
// This is a concrete class because if we are not using the MessageRelayer,

test/MessageRelayer/FundAmountScenarios.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {GenericRecipient} from "./GenericRecipient.t.sol";
77
import {InitialState} from "./InitialState.t.sol";
88
import {IETHBridge} from "src/protocol/IETHBridge.sol";
99

10-
contract VaryingFundAmount is DepositRecipientIsMessageRelayer {
10+
contract VaryingFundAmounts is DepositRecipientIsMessageRelayer {
1111
function setUp() public override {
1212
super.setUp();
1313
}

test/MessageRelayer/GenericRecipient.t.sol

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.28;
33

4-
contract GenericRecipient {
4+
import {IMessageRelayer} from "src/protocol/IMessageRelayer.sol";
5+
6+
interface IGenericRecipient {
7+
function setSuccess(bool _callWillSucceed) external;
8+
function setReentrancyAttack(bool _shouldAttack) external;
9+
}
10+
11+
contract GenericRecipient is IGenericRecipient {
512
bool private callWillSucceed = true;
13+
bool private shouldReenterAttack = false;
14+
address private relayer;
15+
uint256 private reentrancyCounter = 0;
616

717
error CallFailed();
818

919
event FunctionCalled();
20+
event ReentrancyAttempt(uint256 counter);
21+
22+
constructor(address _relayer) {
23+
relayer = _relayer;
24+
}
1025

1126
function setSuccess(bool _callWillSucceed) external {
1227
callWillSucceed = _callWillSucceed;
1328
}
1429

30+
function setReentrancyAttack(bool _shouldAttack) external {
31+
shouldReenterAttack = _shouldAttack;
32+
}
33+
1534
fallback() external payable {
1635
_simulateFunctionCall();
1736
}
@@ -23,5 +42,12 @@ contract GenericRecipient {
2342
function _simulateFunctionCall() internal {
2443
require(callWillSucceed, CallFailed());
2544
emit FunctionCalled();
45+
46+
if (shouldReenterAttack) {
47+
reentrancyCounter++;
48+
emit ReentrancyAttempt(reentrancyCounter);
49+
50+
IMessageRelayer(relayer).receiveMessage(address(this), 0, address(this), 0, "0x");
51+
}
2652
}
2753
}

test/MessageRelayer/InitialState.t.sol

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@ abstract contract InitialState is Test {
3030
MockSignalService signalService = new MockSignalService();
3131
address trustedCommitmentPublisher = _randomAddress("trustedCommitmentPublisher");
3232
address counterpart = _randomAddress("counterpart");
33-
to = new GenericRecipient();
34-
relayerSelectedTipRecipient = new GenericRecipient();
35-
userSelectedTipRecipient = new GenericRecipient();
3633
ETHBridge bridge = new ETHBridge(address(signalService), trustedCommitmentPublisher, counterpart);
3734
vm.deal(address(bridge), amount);
3835

3936
messageRelayer = new MessageRelayer(address(bridge));
4037

38+
to = new GenericRecipient(address(messageRelayer));
39+
relayerSelectedTipRecipient = new GenericRecipient(address(messageRelayer));
40+
userSelectedTipRecipient = new GenericRecipient(address(messageRelayer));
41+
4142
ethDeposit = IETHBridge.ETHDeposit({
4243
nonce: 0,
4344
from: _randomAddress("from"),
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
import {DepositRecipientIsMessageRelayer} from "./DepositRecipientScenarios.t.sol";
5+
import {GenericRecipient} from "./GenericRecipient.t.sol";
6+
7+
import {InitialState} from "./InitialState.t.sol";
8+
import {IETHBridge} from "src/protocol/IETHBridge.sol";
9+
10+
contract RelayRecipientRejectsDeposit is DepositRecipientIsMessageRelayer {
11+
function setUp() public override {
12+
super.setUp();
13+
to.setSuccess(false);
14+
}
15+
16+
function test_RelayRecipientRejectsDeposit_relayMessage_shouldRevert() public {
17+
vm.expectRevert(IETHBridge.FailedClaim.selector);
18+
_relayMessage();
19+
}
20+
}
21+
22+
contract RelayRecipientIsReentrant is DepositRecipientIsMessageRelayer {
23+
function setUp() public override {
24+
super.setUp();
25+
to.setReentrancyAttack(true);
26+
}
27+
28+
function test_RelayRecipientReentersReceiveMessage_relayMessage_shouldRevert() public {
29+
vm.expectRevert(IETHBridge.FailedClaim.selector);
30+
_relayMessage();
31+
}
32+
}

0 commit comments

Comments
 (0)