Skip to content

Commit

Permalink
fix: recipient rate limited ISM (#4636)
Browse files Browse the repository at this point in the history
### Description

Add recipient restriction to rate limited ISM. This prevents multiple
recipients from sharing the same rate limit ISM and denial of service
attacks.

### Backward compatibility

No

### Testing

Unit Tests
  • Loading branch information
yorhodes authored Oct 7, 2024
1 parent 7dccf80 commit bb75eba
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-toys-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/core': minor
---

fix: constrain rate limited ISM to a single message recipient
23 changes: 19 additions & 4 deletions solidity/contracts/isms/warp-route/RateLimitedIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ contract RateLimitedIsm is
using Message for bytes;
using TokenMessage for bytes;

address public immutable recipient;

mapping(bytes32 messageId => bool validated) public messageValidated;

modifier validateMessageOnce(bytes calldata _message) {
Expand All @@ -25,14 +27,22 @@ contract RateLimitedIsm is
_;
}

modifier onlyRecipient(bytes calldata _message) {
require(_message.recipientAddress() == recipient, "InvalidRecipient");
_;
}

constructor(
address _mailbox,
uint256 _maxCapacity
) MailboxClient(_mailbox) RateLimited(_maxCapacity) {}
uint256 _maxCapacity,
address _recipient
) MailboxClient(_mailbox) RateLimited(_maxCapacity) {
recipient = _recipient;
}

/// @inheritdoc IInterchainSecurityModule
function moduleType() external pure returns (uint8) {
return uint8(IInterchainSecurityModule.Types.UNUSED);
return uint8(IInterchainSecurityModule.Types.NULL);
}

/**
Expand All @@ -42,7 +52,12 @@ contract RateLimitedIsm is
function verify(
bytes calldata,
bytes calldata _message
) external validateMessageOnce(_message) returns (bool) {
)
external
onlyRecipient(_message)
validateMessageOnce(_message)
returns (bool)
{
require(_isDelivered(_message.id()), "InvalidDeliveredMessage");

uint256 newAmount = _message.body().amount();
Expand Down
23 changes: 20 additions & 3 deletions solidity/test/isms/RateLimitedIsm.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ contract RateLimitedIsmTest is Test {
function setUp() external {
localMailbox = new TestMailbox(ORIGIN);

testRecipient = new TestRecipient();
rateLimitedIsm = new RateLimitedIsm(
address(localMailbox),
MAX_CAPACITY
MAX_CAPACITY,
address(testRecipient)
);
testRecipient = new TestRecipient();

testRecipient.setInterchainSecurityModule(address(rateLimitedIsm));
}

function testRateLimitedIsm_revertsIDeliveredFalse(
bytes calldata _message
uint256 _amount
) external {
bytes memory _message = _encodeTestMessage(_amount);
vm.prank(address(localMailbox));
vm.expectRevert("InvalidDeliveredMessage");
rateLimitedIsm.verify(bytes(""), _message);
Expand All @@ -62,6 +64,21 @@ contract RateLimitedIsmTest is Test {
rateLimitedIsm.verify(bytes(""), encodedMessage);
}

function test_verifyOnlyRecipient(uint128 _amount) external {
bytes memory _message = MessageUtils.formatMessage(
uint8(3),
uint32(1),
ORIGIN,
WARP_ROUTE_ADDR.addressToBytes32(),
ORIGIN,
~address(testRecipient).addressToBytes32(), // bad recipient
TokenMessage.format(bytes32(""), _amount, bytes(""))
);

vm.expectRevert("InvalidRecipient");
rateLimitedIsm.verify(bytes(""), _message);
}

function _encodeTestMessage(
uint256 _amount
) internal view returns (bytes memory) {
Expand Down

0 comments on commit bb75eba

Please sign in to comment.