Skip to content

Commit b42535a

Browse files
committed
evm: add max payload size check
1 parent 1a7aae1 commit b42535a

File tree

5 files changed

+68
-12
lines changed

5 files changed

+68
-12
lines changed

evm/src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol

+5
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ contract WormholeTransceiver is
192192
new bytes(0)
193193
);
194194

195+
// Verify that the transceiver message is small enough to be posted on Solana.
196+
if (encodedTransceiverPayload.length > MAX_PAYLOAD_SIZE) {
197+
revert ExceedsMaxPayloadSize(encodedTransceiverPayload.length, MAX_PAYLOAD_SIZE);
198+
}
199+
195200
WormholeTransceiverInstruction memory weIns =
196201
parseWormholeTransceiverInstruction(instruction.payload);
197202

evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol

+7-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ abstract contract WormholeTransceiverState is IWormholeTransceiverState, Transce
2222
using BooleanFlagLib for BooleanFlag;
2323

2424
// ==================== Immutables ===============================================
25+
26+
/// @dev Maximum payload size for any message. Since posting a message on Solana has a
27+
/// maximum size, all messages are restricted to this size. If this program is
28+
/// only used on EVM chains, this restriction can be removed.
29+
uint16 public constant MAX_PAYLOAD_SIZE = 850;
30+
2531
uint8 public immutable consistencyLevel;
2632
IWormhole public immutable wormhole;
2733
IWormholeRelayer public immutable wormholeRelayer;
@@ -34,7 +40,7 @@ abstract contract WormholeTransceiverState is IWormholeTransceiverState, Transce
3440

3541
/// @dev Prefix for all TransceiverMessage payloads
3642
/// This is 0x99'E''W''H'
37-
/// @notice Magic string (constant value set by messaging provider) that idenfies the payload as an transceiver-emitted payload.
43+
/// @notice Magic string (constant value set by messaging provider) that identifies the payload as an transceiver-emitted payload.
3844
/// 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.
3945
bytes4 constant WH_TRANSCEIVER_PAYLOAD_PREFIX = 0x9945FF10;
4046

evm/src/interfaces/IWormholeTransceiver.sol

+6
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ interface IWormholeTransceiver is IWormholeTransceiverState {
5656
/// @param vaaHash The hash of the VAA.
5757
error TransferAlreadyCompleted(bytes32 vaaHash);
5858

59+
/// @notice Error when the payload size exceeds the maximum allowed size.
60+
/// @dev Selector: 0xf39ac4ba.
61+
/// @param payloadSize The size of the payload.
62+
/// @param maxPayloadSize The maximum allowed size.
63+
error ExceedsMaxPayloadSize(uint256 payloadSize, uint256 maxPayloadSize);
64+
5965
/// @notice Receive an attested message from the verification layer.
6066
/// This function should verify the `encodedVm` and then deliver the attestation
6167
/// to the transceiver NttManager contract.

evm/src/interfaces/IWormholeTransceiverState.sol

+3
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,7 @@ interface IWormholeTransceiverState {
127127
/// @param chainId The Wormhole chain ID to set.
128128
/// @param isRelayingEnabled A boolean indicating whether special relaying is enabled.
129129
function setIsSpecialRelayingEnabled(uint16 chainId, bool isRelayingEnabled) external;
130+
131+
/// @notice Returns the maximum payload size for a Wormhole Transceiver message.
132+
function MAX_PAYLOAD_SIZE() external view returns (uint16);
130133
}

evm/test/NonFungibleNttManager.t.sol

+47-11
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,11 @@ contract TestNonFungibleNttManager is Test {
6161
address nft,
6262
IManagerBase.Mode _mode,
6363
uint16 _chainId,
64-
bool shouldInitialize
64+
bool shouldInitialize,
65+
uint8 _tokenIdWidth
6566
) internal returns (INonFungibleNttManager) {
6667
NonFungibleNttManager implementation =
67-
new NonFungibleNttManager(address(nft), tokenIdWidth, _mode, _chainId);
68+
new NonFungibleNttManager(address(nft), _tokenIdWidth, _mode, _chainId);
6869

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

114115
// Managers.
115-
managerOne =
116-
deployNonFungibleManager(address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, true);
117-
managerTwo =
118-
deployNonFungibleManager(address(nftTwo), IManagerBase.Mode.BURNING, chainIdTwo, true);
119-
managerThree =
120-
deployNonFungibleManager(address(nftOne), IManagerBase.Mode.BURNING, chainIdThree, true);
116+
managerOne = deployNonFungibleManager(
117+
address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, true, tokenIdWidth
118+
);
119+
managerTwo = deployNonFungibleManager(
120+
address(nftTwo), IManagerBase.Mode.BURNING, chainIdTwo, true, tokenIdWidth
121+
);
122+
managerThree = deployNonFungibleManager(
123+
address(nftOne), IManagerBase.Mode.BURNING, chainIdThree, true, tokenIdWidth
124+
);
121125

122126
// Wormhole Transceivers.
123127
transceiverOne = deployWormholeTranceiver(address(managerOne));
@@ -214,8 +218,9 @@ contract TestNonFungibleNttManager is Test {
214218
function test_cannotInitalizeNotDeployer() public {
215219
// Don't initialize.
216220
vm.prank(owner);
217-
INonFungibleNttManager dummyManager =
218-
deployNonFungibleManager(address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, false);
221+
INonFungibleNttManager dummyManager = deployNonFungibleManager(
222+
address(nftOne), IManagerBase.Mode.LOCKING, chainIdOne, false, tokenIdWidth
223+
);
219224

220225
vm.prank(makeAddr("notOwner"));
221226
vm.expectRevert(
@@ -630,6 +635,38 @@ contract TestNonFungibleNttManager is Test {
630635
);
631636
}
632637

638+
function test_cannotTransferPayloadSizeExceeded() public {
639+
// Deploy manager with 32 byte tokenIdWidth.
640+
INonFungibleNttManager manager = deployNonFungibleManager(
641+
address(nftOne), IManagerBase.Mode.BURNING, chainIdThree, true, 32
642+
);
643+
WormholeTransceiver transceiver = deployWormholeTranceiver(address(manager));
644+
transceiver.setWormholePeer(chainIdTwo, toWormholeFormat(makeAddr("random")));
645+
manager.setTransceiver(address(transceiver));
646+
manager.setPeer(chainIdTwo, toWormholeFormat(makeAddr("random")));
647+
648+
// Since the NonFungibleNtt payload is currently 180 bytes (without the tokenIds),
649+
// we should be able to cause the error by transferring with 21 tokenIds.
650+
// floor((850 - 180) / 33) + 1 (32 bytes per tokenId, 1 byte for length).
651+
uint256 nftCount = 21;
652+
uint256 startId = 0;
653+
654+
address recipient = makeAddr("recipient");
655+
uint256[] memory tokenIds = _mintNftBatch(nftOne, recipient, nftCount, startId);
656+
657+
vm.startPrank(recipient);
658+
nftOne.setApprovalForAll(address(managerOne), true);
659+
660+
vm.expectRevert(
661+
abi.encodeWithSelector(
662+
IWormholeTransceiver.ExceedsMaxPayloadSize.selector,
663+
873,
664+
transceiver.MAX_PAYLOAD_SIZE()
665+
)
666+
);
667+
manager.transfer(tokenIds, chainIdTwo, toWormholeFormat(recipient), new bytes(1));
668+
}
669+
633670
function test_cannotTransferDuplicateNfts() public {
634671
uint256 nftCount = 2;
635672
uint256 startId = 0;
@@ -1067,4 +1104,3 @@ contract TestNonFungibleNttManager is Test {
10671104

10681105
// TODO:
10691106
// 1) Relayer test
1070-
// 2) Add max payload size and associated tests

0 commit comments

Comments
 (0)