diff --git a/contracts/pyth-governance-v1.clar b/contracts/pyth-governance-v1.clar index 5cd2fdd..07e555e 100644 --- a/contracts/pyth-governance-v1.clar +++ b/contracts/pyth-governance-v1.clar @@ -50,6 +50,8 @@ (define-constant ERR_INVALID_PTGM (err u4007)) ;; Error not standard principal (define-constant ERR_NOT_STANDARD_PRINCIPAL (err u4008)) +;; Error Ptgm overlay bytes +(define-constant ERR_PTGM_CHECK_OVERLAY (err u4009)) (define-data-var governance-data-source { emitter-chain: uint, emitter-address: (buff 32) } @@ -365,7 +367,8 @@ (cursor-target-chain-id (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-buff-2 (get next cursor-action)) ERR_INVALID_PTGM)) (cursor-body (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-buff-8192-max (get next cursor-target-chain-id) none) - ERR_INVALID_PTGM))) + ERR_INVALID_PTGM)) + (overlay-check (asserts! (is-eq (get pos (get next cursor-body)) (len ptgm-bytes)) ERR_PTGM_CHECK_OVERLAY))) ;; Check magic bytes (asserts! (is-eq (get value cursor-magic) PTGM_MAGIC) ERR_INVALID_PTGM) ;; Check target-chain-id @@ -389,7 +392,8 @@ (cursor-mantissa (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-64 (get next cursor-ptgm-body)) ERR_INVALID_ACTION_PAYLOAD)) (cursor-exponent (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-64 (get next cursor-mantissa)) - ERR_INVALID_ACTION_PAYLOAD))) + ERR_INVALID_ACTION_PAYLOAD)) + (overlay-check (asserts! (is-eq (get pos (get next cursor-exponent)) (len ptgm-body)) ERR_PTGM_CHECK_OVERLAY))) (ok { mantissa: (get value cursor-mantissa), exponent: (get value cursor-exponent) @@ -398,7 +402,8 @@ (define-private (parse-and-verify-stale-price-threshold (ptgm-body (buff 8192))) (let ((cursor-ptgm-body (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 new ptgm-body none)) (cursor-stale-price-threshold (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-64 (get next cursor-ptgm-body)) - ERR_INVALID_ACTION_PAYLOAD))) + ERR_INVALID_ACTION_PAYLOAD)) + (overlay-check (asserts! (is-eq (get pos (get next cursor-stale-price-threshold)) (len ptgm-body)) ERR_PTGM_CHECK_OVERLAY))) (ok (get value cursor-stale-price-threshold)))) (define-private (parse-and-verify-governance-data-source (ptgm-body (buff 8192))) @@ -408,7 +413,8 @@ (cursor-emitter-sequence (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-64 (get next cursor-emitter-chain)) ERR_INVALID_ACTION_PAYLOAD)) (cursor-emitter-address (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-buff-32 (get next cursor-emitter-sequence)) - ERR_INVALID_ACTION_PAYLOAD))) + ERR_INVALID_ACTION_PAYLOAD)) + (overlay-check (asserts! (is-eq (get pos (get next cursor-emitter-address)) (len ptgm-body)) ERR_PTGM_CHECK_OVERLAY))) (ok { emitter-chain: (get value cursor-emitter-chain), emitter-sequence: (get value cursor-emitter-sequence), diff --git a/contracts/pyth-pnau-decoder-v1.clar b/contracts/pyth-pnau-decoder-v1.clar index 6d1a3c8..fa4a007 100644 --- a/contracts/pyth-pnau-decoder-v1.clar +++ b/contracts/pyth-pnau-decoder-v1.clar @@ -42,6 +42,8 @@ (define-constant ERR_UNAUTHORIZED_FLOW (err u2404)) ;; Price update not signed by an authorized source (define-constant ERR_UNAUTHORIZED_PRICE_UPDATE (err u2401)) +;; VAA buffer has unused, extra leading bytes (overlay) +(define-constant ERR_OVERLAY_PRESENT (err u2402)) ;;;; Public functions (define-public (decode-and-verify-price-feeds (pnau-bytes (buff 8192)) (wormhole-core-address )) @@ -132,7 +134,7 @@ (define-private (parse-and-verify-prices-updates (bytes (buff 8192)) (merkle-root-hash (buff 20))) (let ((cursor-num-updates (try! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-8 { bytes: bytes, pos: u0 }))) (cursor-updates-bytes (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 slice (get next cursor-num-updates) none)) - (updates (get result (fold parse-price-info-and-proof cursor-updates-bytes { + (updates-data (fold parse-price-info-and-proof cursor-updates-bytes { result: (list), cursor: { index: u0, @@ -140,12 +142,15 @@ }, bytes: cursor-updates-bytes, limit: (get value cursor-num-updates) - }))) + })) + (updates (get result updates-data)) (merkle-proof-checks-success (get result (fold check-merkle-proof updates { result: true, merkle-root-hash: merkle-root-hash })))) (asserts! merkle-proof-checks-success MERKLE_ROOT_MISMATCH) + ;; Overlay check; 1 is added because 1 byte is used to store "cursor-num-updates" + (asserts! (is-eq (+ u1 (get next-update-index (get cursor updates-data))) (len bytes)) ERR_OVERLAY_PRESENT) (ok updates))) (define-private (check-merkle-proof diff --git a/contracts/wormhole/wormhole-core-v2.clar b/contracts/wormhole/wormhole-core-v2.clar index b72f095..199643b 100644 --- a/contracts/wormhole/wormhole-core-v2.clar +++ b/contracts/wormhole/wormhole-core-v2.clar @@ -70,6 +70,8 @@ (define-constant ERR_GSU_CHECK_EMITTER (err u1305)) ;; First guardian set is not being updated by the deployer (define-constant ERR_NOT_DEPLOYER (err u1306)) +;; Overlay present in vaa bytes +(define-constant ERR_GSU_CHECK_OVERLAY (err u1307)) ;; Guardian set upgrade emitting address (define-constant GSU-EMITTING-ADDRESS 0x0000000000000000000000000000000000000000000000000000000000000004) @@ -147,6 +149,7 @@ ERR_VAA_PARSING_CONSISTENCY_LEVEL)) (cursor-payload (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-buff-8192-max (get next cursor-consistency-level) none) ERR_VAA_PARSING_PAYLOAD)) + (overlay-check (asserts! (is-eq (get pos (get next cursor-payload)) (len vaa-bytes)) ERR_GSU_CHECK_OVERLAY)) (public-keys-results (fold batch-recover-public-keys (get value cursor-signatures) { @@ -348,6 +351,7 @@ ERR_GSU_PARSING_GUARDIAN_LEN)) (guardians-bytes (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-buff-8192-max (get next cursor-guardians-count) (some (* (get value cursor-guardians-count) u20))) ERR_GSU_PARSING_GUARDIANS_BYTES)) + (overlay-check (asserts! (is-eq (get pos (get next guardians-bytes)) (len bytes)) ERR_GSU_CHECK_OVERLAY)) (guardians-cues (get result (fold is-guardian-cue (get value guardians-bytes) { cursor: u0, result: (list) }))) (eth-addresses (get result (fold parse-guardian guardians-cues { bytes: (get value guardians-bytes), result: (list) })))) ;; Ensure that this message was emitted from authorized module