Skip to content

Commit 4718928

Browse files
committed
bugfix incorrect vaa hash calculation and implement tests
1 parent e19013d commit 4718928

9 files changed

+1492
-16
lines changed

gen/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cctpDomains_TARGET = constants/CCTPDomains.sol
55
fnGeneratorTarget = ../src/$($(1)_TARGET)
66
GENERATOR_TARGETS = $(foreach generator,$(GENERATORS),$(call fnGeneratorTarget,$(generator)))
77

8-
TEST_WRAPPERS = BytesParsing QueryResponse
8+
TEST_WRAPPERS = BytesParsing QueryResponse VaaLib TokenBridgeMessages CctpMessages
99

1010
fnTestWrapperTarget = ../test/generated/$(1)TestWrapper.sol
1111
TEST_WRAPPER_TARGETS =\

src/constants/CctpDomains.sol

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: Apache 2
2+
pragma solidity ^0.8.0;
3+
4+
// This file is auto-generated by gen/cctpDomains.ts.
5+
6+
uint32 constant CCTP_DOMAIN_ETHEREUM = 0;
7+
uint32 constant CCTP_DOMAIN_AVALANCHE = 1;
8+
uint32 constant CCTP_DOMAIN_OPTIMISM = 2;
9+
uint32 constant CCTP_DOMAIN_ARBITRUM = 3;
10+
uint32 constant CCTP_DOMAIN_SOLANA = 5;
11+
uint32 constant CCTP_DOMAIN_BASE = 6;
12+
uint32 constant CCTP_DOMAIN_POLYGON = 7;
13+
uint32 constant CCTP_DOMAIN_SUI = 8;
14+
15+
// Additional Testnet mappings:
16+
uint32 constant CCTP_DOMAIN_SEPOLIA = 0;
17+
uint32 constant CCTP_DOMAIN_OPTIMISM_SEPOLIA = 2;
18+
uint32 constant CCTP_DOMAIN_ARBITRUM_SEPOLIA = 3;
19+
uint32 constant CCTP_DOMAIN_BASE_SEPOLIA = 6;

src/libraries/VaaLib.sol

+43-10
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,23 @@ library VaaLib {
278278
(vm, ) = decodeVmStructMemUnchecked(encodedVaa, 0, encodedVaa.length);
279279
}
280280

281+
function decodeVaaStructCd(
282+
bytes calldata encodedVaa
283+
) internal pure returns (Vaa memory vaa) {
284+
uint envelopeOffset;
285+
(vaa.header, envelopeOffset) = decodeVaaHeaderStructCdUnchecked(encodedVaa);
286+
287+
uint payloadOffset;
288+
(vaa.envelope, payloadOffset) = decodeVaaEnvelopeStructCdUnchecked(encodedVaa, envelopeOffset);
289+
vaa.payload = decodeVaaPayloadCd(encodedVaa, payloadOffset);
290+
}
291+
292+
function decodeVaaStructMem(
293+
bytes memory encodedVaa
294+
) internal pure returns (Vaa memory vaa) {
295+
(vaa, ) = decodeVaaStructMemUnchecked(encodedVaa, 0, encodedVaa.length);
296+
}
297+
281298
function decodeVaaEssentialsCd(
282299
bytes calldata encodedVaa
283300
) internal pure returns (
@@ -488,9 +505,10 @@ library VaaLib {
488505
bytes memory encoded,
489506
uint envelopeOffset,
490507
uint vaaLength
491-
) internal pure returns (bytes32) {
492-
return keccak256SliceUnchecked(encoded, envelopeOffset, vaaLength);
493-
}
508+
) internal pure returns (bytes32) { unchecked {
509+
envelopeOffset.checkBound(vaaLength);
510+
return keccak256SliceUnchecked(encoded, envelopeOffset, vaaLength - envelopeOffset);
511+
}}
494512

495513
//see WARNING box at the top
496514
function calcSingleHash(Vaa memory vaa) internal pure returns (bytes32) {
@@ -553,6 +571,21 @@ library VaaLib {
553571
) = decodeVaaBodyMemUnchecked(encoded, envelopeOffset, vaaLength);
554572
}
555573

574+
function decodeVaaStructMemUnchecked(
575+
bytes memory encoded,
576+
uint headerOffset,
577+
uint vaaLength
578+
) internal pure returns (Vaa memory vaa, uint newOffset) {
579+
uint envelopeOffset;
580+
(vaa.header.guardianSetIndex, vaa.header.signatures, envelopeOffset) =
581+
decodeVaaHeaderMemUnchecked(encoded, headerOffset);
582+
583+
uint payloadOffset;
584+
(vaa.envelope, payloadOffset) = decodeVaaEnvelopeStructMemUnchecked(encoded, envelopeOffset);
585+
586+
(vaa.payload, newOffset) = decodeVaaPayloadMemUnchecked(encoded, payloadOffset, vaaLength);
587+
}
588+
556589
function decodeVaaBodyCd(
557590
bytes calldata encodedVaa,
558591
uint envelopeOffset
@@ -643,7 +676,7 @@ library VaaLib {
643676
payloadOffset = offset;
644677
}
645678

646-
function decodeVaaEnvelopeStructCd(
679+
function decodeVaaEnvelopeStructCdUnchecked(
647680
bytes calldata encodedVaa,
648681
uint envelopeOffset
649682
) internal pure returns (VaaEnvelope memory envelope, uint payloadOffset) {
@@ -679,7 +712,7 @@ library VaaLib {
679712
payloadOffset = offset;
680713
}
681714

682-
function decodeVaaEnvelopeStructMem(
715+
function decodeVaaEnvelopeStructMemUnchecked(
683716
bytes memory encoded,
684717
uint envelopeOffset
685718
) internal pure returns (VaaEnvelope memory envelope, uint payloadOffset) {
@@ -808,19 +841,19 @@ library VaaLib {
808841

809842
function decodeVaaPayloadCd(
810843
bytes calldata encodedVaa,
811-
uint offset
844+
uint payloadOffset
812845
) internal pure returns (bytes calldata payload) {
813-
payload = _decodeRemainderCd(encodedVaa, offset);
846+
payload = _decodeRemainderCd(encodedVaa, payloadOffset);
814847
}
815848

816849
function decodeVaaPayloadMemUnchecked(
817850
bytes memory encoded,
818-
uint offset,
851+
uint payloadOffset,
819852
uint vaaLength
820853
) internal pure returns (bytes memory payload, uint newOffset) {
821854
//check to avoid underflow in following subtraction
822-
offset.checkBound(vaaLength);
823-
(payload, newOffset) = encoded.sliceMemUnchecked(offset, vaaLength - offset);
855+
payloadOffset.checkBound(vaaLength);
856+
(payload, newOffset) = encoded.sliceMemUnchecked(payloadOffset, vaaLength - payloadOffset);
824857
}
825858

826859
// ------------ Encoding ------------

test/QueryResponse.t.sol

+14-5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ contract QueryResponseTest is Test {
6060
return string(abi.encodePacked(functionName, cd ? "Cd" : "Mem", parameters));
6161
}
6262

63+
function runBoth(function(bool) test) internal {
64+
test(true);
65+
test(false);
66+
}
67+
6368
function _verifyQueryResponseRaw(
6469
bool cd,
6570
bytes memory resp,
@@ -192,7 +197,7 @@ contract QueryResponseTest is Test {
192197
);
193198
}
194199

195-
function test_calcPrefixedResponseHash(bool cd) public {
200+
function calcPrefixedResponseHash(bool cd) internal {
196201
bytes memory resp = concatenateQueryResponseBytesOffChain(version, senderChainId, signature, queryRequestVersion, queryRequestNonce, numPerChainQueries, perChainQueries, numPerChainResponses, perChainResponses);
197202

198203
(bool success, bytes memory encodedResult) =
@@ -205,13 +210,15 @@ contract QueryResponseTest is Test {
205210
bytes32 expectedDigest = 0x5b84b19c68ee0b37899230175a92ee6eda4c5192e8bffca1d057d811bb3660e2;
206211
assertEq(digest, expectedDigest);
207212
}
213+
function test_calcPrefixedResponseHash() public { runBoth(calcPrefixedResponseHash); }
208214

209-
function test_verifyQueryResponse(bool cd) public {
215+
function verifyQueryResponse(bool cd) internal {
210216
bytes memory resp = concatenateQueryResponseBytesOffChain(version, senderChainId, signature, queryRequestVersion, queryRequestNonce, numPerChainQueries, perChainQueries, numPerChainResponses, perChainResponses);
211217
_verifyQueryResponse(cd, resp, sign(resp));
212218
}
219+
function test_verifyQueryResponse() public { runBoth(verifyQueryResponse); }
213220

214-
function test_decodeAndVerifyQueryResponse(bool cd) public {
221+
function decodeAndVerifyQueryResponse(bool cd) internal {
215222
bytes memory resp = concatenateQueryResponseBytesOffChain(version, senderChainId, signature, queryRequestVersion, queryRequestNonce, numPerChainQueries, perChainQueries, numPerChainResponses, perChainResponses);
216223
QueryResponse memory r = _decodeAndVerifyQueryResponse(cd, resp, sign(resp));
217224
assertEq(r.version, 1);
@@ -224,8 +231,9 @@ contract QueryResponseTest is Test {
224231
assertEq(r.responses[0].request, hex"00000009307832613631616334020d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000406fdde030d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000418160ddd");
225232
assertEq(r.responses[0].response, hex"0000000002a61ac4c1adff9f6e180309e7d0d94c063338ddc61c1c4474cd6957c960efe659534d040005ff312e4f90c002000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d57726170706564204d6174696300000000000000000000000000000000000000000000200000000000000000000000000000000000000000007ae5649beabeddf889364a");
226233
}
234+
function test_decodeAndVerifyQueryResponse() public { runBoth(decodeAndVerifyQueryResponse); }
227235

228-
function test_decodeEthCallQueryResponse() public {
236+
function test_decodeEthCallQueryResponse() internal {
229237
// Take the data extracted by the previous test and break it down even further.
230238
PerChainQueryResponse memory r = PerChainQueryResponse({
231239
chainId: 5,
@@ -377,10 +385,11 @@ contract QueryResponseTest is Test {
377385

378386
// Start of Solana Stuff ///////////////////////////////////////////////////////////////////////////
379387

380-
function test_verifyQueryResponseForSolana(bool cd) public {
388+
function verifyQueryResponseForSolana(bool cd) internal {
381389
bytes memory resp = concatenateQueryResponseBytesOffChain(version, senderChainId, solanaAccountSignature, solanaAccountQueryRequestVersion, solanaAccountQueryRequestNonce, solanaAccountNumPerChainQueries, solanaAccountPerChainQueries, solanaAccountNumPerChainResponses, solanaAccountPerChainResponses);
382390
_verifyQueryResponse(cd, resp, sign(resp));
383391
}
392+
function test_verifyQueryResponseForSolana() public { runBoth(verifyQueryResponseForSolana); }
384393

385394
function test_decodeSolanaAccountQueryResponse() public {
386395
// Take the data extracted by the previous test and break it down even further.

0 commit comments

Comments
 (0)