Skip to content

Commit 198b107

Browse files
authored
Add useful tbr parse functions (#84)
* Add useful tbr parse functions * Add 'Unchecked' suffix
1 parent cf70b19 commit 198b107

File tree

5 files changed

+261
-11
lines changed

5 files changed

+261
-11
lines changed

src/libraries/TokenBridgeMessages.sol

Lines changed: 146 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ struct TokenBridgeTransferWithPayload {
9797
bytes payload;
9898
}
9999

100+
struct TokenBridgeTransferWithPayloadEssentials {
101+
//uint8 payloadId; //see PAYLOAD_ID_TRANSFER_WITH_PAYLOAD
102+
uint256 normalizedAmount;
103+
bytes32 tokenAddress;
104+
uint16 tokenChainId;
105+
bytes32 fromAddress;
106+
bytes payload;
107+
}
108+
100109
struct TokenBridgeAttestMeta {
101110
//uint8 payloadId; //see PAYLOAD_ID_ATTEST_META
102111
bytes32 tokenAddress;
@@ -372,6 +381,95 @@ library TokenBridgeMessageLib {
372381
) = decodeTransferWithPayloadMem(encoded, offset, length);
373382
}
374383

384+
// TransferWithPayloadEssentials
385+
386+
function decodeTransferWithPayloadEssentialsCd(
387+
bytes calldata encoded
388+
) internal pure returns (
389+
uint256 normalizedAmount,
390+
bytes32 tokenAddress,
391+
uint16 tokenChainId,
392+
bytes32 fromAddress,
393+
bytes calldata payload
394+
) { unchecked {
395+
uint offset = 0;
396+
(normalizedAmount, tokenAddress, tokenChainId, offset) =
397+
_decodeTransferCommonHeaderEssentialsCdUnchecked(encoded, PAYLOAD_ID_TRANSFER_WITH_PAYLOAD);
398+
399+
offset += COMMON_TRANSFER_TO_ADDRESS_SIZE + COMMON_TRANSFER_TO_CHAIN_ID_SIZE;
400+
(fromAddress, offset) = encoded.asBytes32CdUnchecked(offset);
401+
402+
offset.checkBound(encoded.length); //check for underflow
403+
(payload, ) = encoded.sliceCdUnchecked(offset, encoded.length - offset);
404+
}}
405+
406+
function decodeTransferWithPayloadEssentialsStructCd(
407+
bytes calldata encoded
408+
) internal pure returns (TokenBridgeTransferWithPayloadEssentials memory twp) {
409+
( twp.normalizedAmount,
410+
twp.tokenAddress,
411+
twp.tokenChainId,
412+
twp.fromAddress,
413+
twp.payload
414+
) = decodeTransferWithPayloadEssentialsCd(encoded);
415+
}
416+
417+
function decodeTransferWithPayloadEssentialsMem(
418+
bytes memory encoded
419+
) internal pure returns (
420+
uint256 normalizedAmount,
421+
bytes32 tokenAddress,
422+
uint16 tokenChainId,
423+
bytes32 fromAddress,
424+
bytes memory payload
425+
) {
426+
(normalizedAmount, tokenAddress, tokenChainId, fromAddress, payload, ) =
427+
decodeTransferWithPayloadEssentialsMem(encoded, 0, encoded.length);
428+
}
429+
430+
function decodeTransferWithPayloadEssentialsStructMem(
431+
bytes memory encoded
432+
) internal pure returns (TokenBridgeTransferWithPayloadEssentials memory twp) {
433+
(twp, ) = decodeTransferWithPayloadEssentialsStructMem(encoded, 0, encoded.length);
434+
}
435+
436+
function decodeTransferWithPayloadEssentialsMem(
437+
bytes memory encoded,
438+
uint offset,
439+
uint length
440+
) internal pure returns (
441+
uint256 normalizedAmount,
442+
bytes32 tokenAddress,
443+
uint16 tokenChainId,
444+
bytes32 fromAddress,
445+
bytes memory payload,
446+
uint newOffset
447+
) { unchecked {
448+
(normalizedAmount, tokenAddress, tokenChainId, offset) =
449+
_decodeTransferCommonHeaderEssentialsMemUnchecked(encoded, offset, PAYLOAD_ID_TRANSFER_WITH_PAYLOAD);
450+
451+
offset += COMMON_TRANSFER_TO_ADDRESS_SIZE + COMMON_TRANSFER_TO_CHAIN_ID_SIZE;
452+
(fromAddress, offset) = encoded.asBytes32MemUnchecked(offset);
453+
454+
offset.checkBound(length); //check for underflow
455+
(payload, newOffset) = encoded.sliceMemUnchecked(offset, length - offset);
456+
457+
}}
458+
459+
function decodeTransferWithPayloadEssentialsStructMem(
460+
bytes memory encoded,
461+
uint offset,
462+
uint length
463+
) internal pure returns (TokenBridgeTransferWithPayloadEssentials memory twp, uint newOffset) {
464+
( twp.normalizedAmount,
465+
twp.tokenAddress,
466+
twp.tokenChainId,
467+
twp.fromAddress,
468+
twp.payload,
469+
newOffset
470+
) = decodeTransferWithPayloadEssentialsMem(encoded, offset, length);
471+
}
472+
375473
// AttestMeta
376474

377475
function decodeAttestMetaCd(
@@ -554,15 +652,13 @@ library TokenBridgeMessageLib {
554652

555653
// ------------ Private ------------
556654

557-
function _decodeTransferCommonHeaderCdUnchecked(
655+
function _decodeTransferCommonHeaderEssentialsCdUnchecked(
558656
bytes calldata encoded,
559657
uint8 expectedPayloadId
560658
) private pure returns (
561659
uint256 normalizedAmount,
562660
bytes32 tokenAddress,
563661
uint16 tokenChainId,
564-
bytes32 toAddress,
565-
uint16 toChainId,
566662
uint newOffset
567663
) {
568664
uint8 payloadId;
@@ -572,21 +668,17 @@ library TokenBridgeMessageLib {
572668
(normalizedAmount, offset) = encoded.asUint256CdUnchecked(offset);
573669
(tokenAddress, offset) = encoded.asBytes32CdUnchecked(offset);
574670
(tokenChainId, offset) = encoded.asUint16CdUnchecked(offset);
575-
(toAddress, offset) = encoded.asBytes32CdUnchecked(offset);
576-
(toChainId, offset) = encoded.asUint16CdUnchecked(offset);
577671
newOffset = offset;
578672
}
579673

580-
function _decodeTransferCommonHeaderMemUnchecked(
674+
function _decodeTransferCommonHeaderEssentialsMemUnchecked(
581675
bytes memory encoded,
582676
uint offset,
583677
uint8 expectedPayloadId
584678
) private pure returns (
585679
uint256 normalizedAmount,
586680
bytes32 tokenAddress,
587681
uint16 tokenChainId,
588-
bytes32 toAddress,
589-
uint16 toChainId,
590682
uint newOffset
591683
) {
592684
uint8 payloadId;
@@ -595,8 +687,52 @@ library TokenBridgeMessageLib {
595687
(normalizedAmount, offset) = encoded.asUint256MemUnchecked(offset);
596688
(tokenAddress, offset) = encoded.asBytes32MemUnchecked(offset);
597689
(tokenChainId, offset) = encoded.asUint16MemUnchecked(offset);
598-
(toAddress, offset) = encoded.asBytes32MemUnchecked(offset);
599-
(toChainId, offset) = encoded.asUint16MemUnchecked(offset);
690+
newOffset = offset;
691+
}
692+
693+
function _decodeTransferCommonHeaderCdUnchecked(
694+
bytes calldata encoded,
695+
uint8 expectedPayloadId
696+
) private pure returns (
697+
uint256 normalizedAmount,
698+
bytes32 tokenAddress,
699+
uint16 tokenChainId,
700+
bytes32 toAddress,
701+
uint16 toChainId,
702+
uint newOffset
703+
) {
704+
uint offset;
705+
(
706+
normalizedAmount,
707+
tokenAddress,
708+
tokenChainId,
709+
offset
710+
) = _decodeTransferCommonHeaderEssentialsCdUnchecked(encoded, expectedPayloadId);
711+
(toAddress, offset) = encoded.asBytes32CdUnchecked(offset);
712+
(toChainId, offset) = encoded.asUint16CdUnchecked(offset);
713+
newOffset = offset;
714+
}
715+
716+
function _decodeTransferCommonHeaderMemUnchecked(
717+
bytes memory encoded,
718+
uint offset,
719+
uint8 expectedPayloadId
720+
) private pure returns (
721+
uint256 normalizedAmount,
722+
bytes32 tokenAddress,
723+
uint16 tokenChainId,
724+
bytes32 toAddress,
725+
uint16 toChainId,
726+
uint newOffset
727+
) {
728+
(
729+
normalizedAmount,
730+
tokenAddress,
731+
tokenChainId,
732+
offset
733+
) = _decodeTransferCommonHeaderEssentialsMemUnchecked(encoded, offset, expectedPayloadId);
734+
(toAddress, offset) = encoded.asBytes32MemUnchecked(offset);
735+
(toChainId, offset) = encoded.asUint16MemUnchecked(offset);
600736
newOffset = offset;
601737
}
602738
}

src/libraries/VaaLib.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,24 @@ library VaaLib {
436436
) = decodeVaaBodyMemUnchecked(encodedVaa, 0, encodedVaa.length);
437437
}
438438

439+
function decodeEmitterChainIdCdUnchecked(
440+
bytes calldata encodedVaa
441+
) internal pure returns (uint16 emitterChainId) {
442+
checkVaaVersionCd(encodedVaa);
443+
uint envelopeOffset = skipVaaHeaderCd(encodedVaa);
444+
uint offset = envelopeOffset + ENVELOPE_EMITTER_CHAIN_ID_OFFSET;
445+
(emitterChainId, ) = encodedVaa.asUint16CdUnchecked(offset);
446+
}
447+
448+
function decodeEmitterChainIdMemUnchecked(
449+
bytes memory encodedVaa
450+
) internal pure returns (uint16 emitterChainId) {
451+
checkVaaVersionMemUnchecked(encodedVaa, 0);
452+
uint envelopeOffset = skipVaaHeaderMemUnchecked(encodedVaa, 0);
453+
uint offset = envelopeOffset + ENVELOPE_EMITTER_CHAIN_ID_OFFSET;
454+
(emitterChainId, ) = encodedVaa.asUint16MemUnchecked(offset);
455+
}
456+
439457
// ------------ Advanced Decoding Functions ------------
440458

441459
function asIWormholeSignatures(

test/WormholeMessages.t.sol

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,21 @@ contract WormholeMessagesTest is Test {
273273
bool cd,
274274
bytes memory encoded,
275275
bool expectSuccess
276+
) private returns (bytes memory) {
277+
return callWithBytes(wrapper, functionName, cd, false, encoded, expectSuccess);
278+
}
279+
280+
function callWithBytes(
281+
address wrapper,
282+
string memory functionName,
283+
bool cd,
284+
bool uc,
285+
bytes memory encoded,
286+
bool expectSuccess
276287
) private returns (bytes memory) {
277288
(bool success, bytes memory encodedResult) =
278289
wrapper.staticcall(abi.encodeWithSignature(
279-
withDataLocationTag(functionName, cd, false, "(bytes)"),
290+
withDataLocationTag(functionName, cd, uc, "(bytes)"),
280291
encoded
281292
));
282293
assertEq(success, expectSuccess);
@@ -520,6 +531,22 @@ contract WormholeMessagesTest is Test {
520531
assertEq(transfer.payload, expected.payload);
521532
}
522533
function testDecodingTwpPayload() public { runBoth(decodingTwpPayload); }
534+
535+
function decodingTwpPayloadEssentials(bool cd) internal {
536+
TokenBridgeTransferWithPayloadEssentials memory transfer = abi.decode(
537+
callWithBytes(tbLibWrapper, "decodeTransferWithPayloadEssentialsStruct", cd, twpVaaPayload(), true),
538+
(TokenBridgeTransferWithPayloadEssentials)
539+
);
540+
TokenBridgeTransferWithPayload memory expected = decodedTwpStruct();
541+
542+
assertEq(transfer.normalizedAmount, expected.normalizedAmount);
543+
assertEq(transfer.tokenAddress, expected.tokenAddress);
544+
assertEq(transfer.tokenChainId, expected.tokenChainId);
545+
assertEq(transfer.fromAddress, expected.fromAddress);
546+
assertEq(transfer.payload, expected.payload);
547+
}
548+
function testDecodingTwpPayloadEssentials() public { runBoth(decodingTwpPayloadEssentials); }
549+
523550
// ----
524551

525552
function decodingAmVaaVm(bool cd) internal {
@@ -565,4 +592,14 @@ contract WormholeMessagesTest is Test {
565592
assertEq(transfer.name, expected.name);
566593
}
567594
function testDecodingAmPayload() public { runBoth(decodingAmPayload); }
595+
596+
function decodingEmitterChainId(bool cd) internal {
597+
uint16 emitterChainId = abi.decode(
598+
callWithBytes(vaaLibWrapper, "decodeEmitterChainId", cd, true, amVaa(), true),
599+
(uint16)
600+
);
601+
602+
assertEq(emitterChainId, amVaaVm().emitterChainId);
603+
}
604+
function testDecodingEmitterChainId() public { runBoth(decodingEmitterChainId); }
568605
}

test/generated/TokenBridgeMessagesTestWrapper.sol

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,57 @@ contract TokenBridgeMessageLibTestWrapper {
110110
return TokenBridgeMessageLib.decodeTransferWithPayloadStructMem(encoded, offset, length);
111111
}
112112

113+
function decodeTransferWithPayloadEssentialsCd(bytes calldata encoded) external pure returns (
114+
uint256 normalizedAmount,
115+
bytes32 tokenAddress,
116+
uint16 tokenChainId,
117+
bytes32 fromAddress,
118+
bytes calldata payload
119+
) {
120+
return TokenBridgeMessageLib.decodeTransferWithPayloadEssentialsCd(encoded);
121+
}
122+
123+
function decodeTransferWithPayloadEssentialsStructCd(bytes calldata encoded) external pure returns (TokenBridgeTransferWithPayloadEssentials memory twp) {
124+
return TokenBridgeMessageLib.decodeTransferWithPayloadEssentialsStructCd(encoded);
125+
}
126+
127+
function decodeTransferWithPayloadEssentialsMem(bytes calldata encoded) external pure returns (
128+
uint256 normalizedAmount,
129+
bytes32 tokenAddress,
130+
uint16 tokenChainId,
131+
bytes32 fromAddress,
132+
bytes memory payload
133+
) {
134+
return TokenBridgeMessageLib.decodeTransferWithPayloadEssentialsMem(encoded);
135+
}
136+
137+
function decodeTransferWithPayloadEssentialsStructMem(bytes calldata encoded) external pure returns (TokenBridgeTransferWithPayloadEssentials memory twp) {
138+
return TokenBridgeMessageLib.decodeTransferWithPayloadEssentialsStructMem(encoded);
139+
}
140+
141+
function decodeTransferWithPayloadEssentialsMem(
142+
bytes calldata encoded,
143+
uint offset,
144+
uint length
145+
) external pure returns (
146+
uint256 normalizedAmount,
147+
bytes32 tokenAddress,
148+
uint16 tokenChainId,
149+
bytes32 fromAddress,
150+
bytes memory payload,
151+
uint newOffset
152+
) {
153+
return TokenBridgeMessageLib.decodeTransferWithPayloadEssentialsMem(encoded, offset, length);
154+
}
155+
156+
function decodeTransferWithPayloadEssentialsStructMem(
157+
bytes calldata encoded,
158+
uint offset,
159+
uint length
160+
) external pure returns (TokenBridgeTransferWithPayloadEssentials memory twp, uint newOffset) {
161+
return TokenBridgeMessageLib.decodeTransferWithPayloadEssentialsStructMem(encoded, offset, length);
162+
}
163+
113164
function decodeAttestMetaCd(bytes calldata encoded) external pure returns (
114165
bytes32 tokenAddress,
115166
uint16 tokenChainId,

test/generated/VaaLibTestWrapper.sol

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ contract VaaLibTestWrapper {
102102
return VaaLib.decodeVaaBodyStructMem(encodedVaa);
103103
}
104104

105+
function decodeEmitterChainIdCdUnchecked(bytes calldata encodedVaa) external pure returns (uint16 emitterChainId) {
106+
return VaaLib.decodeEmitterChainIdCdUnchecked(encodedVaa);
107+
}
108+
109+
function decodeEmitterChainIdMemUnchecked(bytes calldata encodedVaa) external pure returns (uint16 emitterChainId) {
110+
return VaaLib.decodeEmitterChainIdMemUnchecked(encodedVaa);
111+
}
112+
105113
function asIWormholeSignatures(GuardianSignature[] calldata signatures) external pure returns (IWormhole.Signature[] memory vmSignatures) {
106114
return VaaLib.asIWormholeSignatures(signatures);
107115
}

0 commit comments

Comments
 (0)