Skip to content

Commit

Permalink
evm: add max payload size check
Browse files Browse the repository at this point in the history
  • Loading branch information
gator-boi committed Mar 19, 2024
1 parent 1a7aae1 commit b42535a
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ contract WormholeTransceiver is
new bytes(0)
);

// Verify that the transceiver message is small enough to be posted on Solana.
if (encodedTransceiverPayload.length > MAX_PAYLOAD_SIZE) {
revert ExceedsMaxPayloadSize(encodedTransceiverPayload.length, MAX_PAYLOAD_SIZE);
}

WormholeTransceiverInstruction memory weIns =
parseWormholeTransceiverInstruction(instruction.payload);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ abstract contract WormholeTransceiverState is IWormholeTransceiverState, Transce
using BooleanFlagLib for BooleanFlag;

// ==================== Immutables ===============================================

/// @dev Maximum payload size for any message. Since posting a message on Solana has a
/// maximum size, all messages are restricted to this size. If this program is
/// only used on EVM chains, this restriction can be removed.
uint16 public constant MAX_PAYLOAD_SIZE = 850;

uint8 public immutable consistencyLevel;
IWormhole public immutable wormhole;
IWormholeRelayer public immutable wormholeRelayer;
Expand All @@ -34,7 +40,7 @@ abstract contract WormholeTransceiverState is IWormholeTransceiverState, Transce

/// @dev Prefix for all TransceiverMessage payloads
/// This is 0x99'E''W''H'
/// @notice Magic string (constant value set by messaging provider) that idenfies the payload as an transceiver-emitted payload.
/// @notice Magic string (constant value set by messaging provider) that identifies the payload as an transceiver-emitted payload.
/// Note that this is not a security critical field. It's meant to be used by messaging providers to identify which messages are Transceiver-related.
bytes4 constant WH_TRANSCEIVER_PAYLOAD_PREFIX = 0x9945FF10;

Expand Down
6 changes: 6 additions & 0 deletions evm/src/interfaces/IWormholeTransceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ interface IWormholeTransceiver is IWormholeTransceiverState {
/// @param vaaHash The hash of the VAA.
error TransferAlreadyCompleted(bytes32 vaaHash);

/// @notice Error when the payload size exceeds the maximum allowed size.
/// @dev Selector: 0xf39ac4ba.
/// @param payloadSize The size of the payload.
/// @param maxPayloadSize The maximum allowed size.
error ExceedsMaxPayloadSize(uint256 payloadSize, uint256 maxPayloadSize);

/// @notice Receive an attested message from the verification layer.
/// This function should verify the `encodedVm` and then deliver the attestation
/// to the transceiver NttManager contract.
Expand Down
3 changes: 3 additions & 0 deletions evm/src/interfaces/IWormholeTransceiverState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,7 @@ interface IWormholeTransceiverState {
/// @param chainId The Wormhole chain ID to set.
/// @param isRelayingEnabled A boolean indicating whether special relaying is enabled.
function setIsSpecialRelayingEnabled(uint16 chainId, bool isRelayingEnabled) external;

/// @notice Returns the maximum payload size for a Wormhole Transceiver message.
function MAX_PAYLOAD_SIZE() external view returns (uint16);
}
58 changes: 47 additions & 11 deletions evm/test/NonFungibleNttManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ contract TestNonFungibleNttManager is Test {
address nft,
IManagerBase.Mode _mode,
uint16 _chainId,
bool shouldInitialize
bool shouldInitialize,
uint8 _tokenIdWidth
) internal returns (INonFungibleNttManager) {
NonFungibleNttManager implementation =
new NonFungibleNttManager(address(nft), tokenIdWidth, _mode, _chainId);
new NonFungibleNttManager(address(nft), _tokenIdWidth, _mode, _chainId);

NonFungibleNttManager proxy =
NonFungibleNttManager(address(new ERC1967Proxy(address(implementation), "")));
Expand Down Expand Up @@ -112,12 +113,15 @@ contract TestNonFungibleNttManager is Test {
nftTwo = new DummyNftMintAndBurn(bytes("https://metadata.dn420.com/y/"));

// Managers.
managerOne =
deployNonFungibleManager(address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, true);
managerTwo =
deployNonFungibleManager(address(nftTwo), IManagerBase.Mode.BURNING, chainIdTwo, true);
managerThree =
deployNonFungibleManager(address(nftOne), IManagerBase.Mode.BURNING, chainIdThree, true);
managerOne = deployNonFungibleManager(
address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, true, tokenIdWidth
);
managerTwo = deployNonFungibleManager(
address(nftTwo), IManagerBase.Mode.BURNING, chainIdTwo, true, tokenIdWidth
);
managerThree = deployNonFungibleManager(
address(nftOne), IManagerBase.Mode.BURNING, chainIdThree, true, tokenIdWidth
);

// Wormhole Transceivers.
transceiverOne = deployWormholeTranceiver(address(managerOne));
Expand Down Expand Up @@ -214,8 +218,9 @@ contract TestNonFungibleNttManager is Test {
function test_cannotInitalizeNotDeployer() public {
// Don't initialize.
vm.prank(owner);
INonFungibleNttManager dummyManager =
deployNonFungibleManager(address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, false);
INonFungibleNttManager dummyManager = deployNonFungibleManager(
address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, false, tokenIdWidth
);

vm.prank(makeAddr("notOwner"));
vm.expectRevert(
Expand Down Expand Up @@ -630,6 +635,38 @@ contract TestNonFungibleNttManager is Test {
);
}

function test_cannotTransferPayloadSizeExceeded() public {
// Deploy manager with 32 byte tokenIdWidth.
INonFungibleNttManager manager = deployNonFungibleManager(
address(nftOne), IManagerBase.Mode.BURNING, chainIdThree, true, 32
);
WormholeTransceiver transceiver = deployWormholeTranceiver(address(manager));
transceiver.setWormholePeer(chainIdTwo, toWormholeFormat(makeAddr("random")));
manager.setTransceiver(address(transceiver));
manager.setPeer(chainIdTwo, toWormholeFormat(makeAddr("random")));

// Since the NonFungibleNtt payload is currently 180 bytes (without the tokenIds),
// we should be able to cause the error by transferring with 21 tokenIds.
// floor((850 - 180) / 33) + 1 (32 bytes per tokenId, 1 byte for length).
uint256 nftCount = 21;
uint256 startId = 0;

address recipient = makeAddr("recipient");
uint256[] memory tokenIds = _mintNftBatch(nftOne, recipient, nftCount, startId);

vm.startPrank(recipient);
nftOne.setApprovalForAll(address(managerOne), true);

vm.expectRevert(
abi.encodeWithSelector(
IWormholeTransceiver.ExceedsMaxPayloadSize.selector,
873,
transceiver.MAX_PAYLOAD_SIZE()
)
);
manager.transfer(tokenIds, chainIdTwo, toWormholeFormat(recipient), new bytes(1));
}

function test_cannotTransferDuplicateNfts() public {
uint256 nftCount = 2;
uint256 startId = 0;
Expand Down Expand Up @@ -1067,4 +1104,3 @@ contract TestNonFungibleNttManager is Test {

// TODO:
// 1) Relayer test
// 2) Add max payload size and associated tests

0 comments on commit b42535a

Please sign in to comment.