fix: recipient rate limited ISM (#4636)

### 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
pull/4640/head
Yorke Rhodes 3 weeks ago committed by GitHub
parent 7dccf80b57
commit bb75eba74a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/breezy-toys-pay.md
  2. 23
      solidity/contracts/isms/warp-route/RateLimitedIsm.sol
  3. 23
      solidity/test/isms/RateLimitedIsm.t.sol

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/core': minor
---
fix: constrain rate limited ISM to a single message recipient

@ -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) {
@ -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);
}
/**
@ -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();

@ -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);
@ -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) {

Loading…
Cancel
Save