diff --git a/Clarinet.toml b/Clarinet.toml index af380ed..10787aa 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -24,8 +24,8 @@ path = 'contracts/pyth-governance-v1.clar' clarity_version = 2 epoch = 2.4 -[contracts.pyth-oracle-v1] -path = 'contracts/pyth-oracle-v1.clar' +[contracts.pyth-oracle-v2] +path = 'contracts/pyth-oracle-v2.clar' clarity_version = 2 epoch = 2.4 diff --git a/contracts/pyth-governance-v1.clar b/contracts/pyth-governance-v1.clar index 4ac891c..4f46dcf 100644 --- a/contracts/pyth-governance-v1.clar +++ b/contracts/pyth-governance-v1.clar @@ -72,7 +72,7 @@ pyth-storage-contract: principal, wormhole-core-contract: principal } { - pyth-oracle-contract: .pyth-oracle-v1, + pyth-oracle-contract: .pyth-oracle-v2, pyth-decoder-contract: .pyth-pnau-decoder-v1, pyth-storage-contract: .pyth-store-v1, wormhole-core-contract: .wormhole-core-v1 diff --git a/contracts/pyth-oracle-v1.clar b/contracts/pyth-oracle-v2.clar similarity index 66% rename from contracts/pyth-oracle-v1.clar rename to contracts/pyth-oracle-v2.clar index aeb5cff..05560d1 100644 --- a/contracts/pyth-oracle-v1.clar +++ b/contracts/pyth-oracle-v2.clar @@ -42,3 +42,23 @@ ;; Charge fee (unwrap! (stx-transfer? fee-amount tx-sender (get address fee-info)) ERR_BALANCE_INSUFFICIENT) (ok updated-prices)))) + +(define-public (decode-price-feeds + (price-feed-bytes (buff 8192)) + (execution-plan { + pyth-storage-contract: , + pyth-decoder-contract: , + wormhole-core-contract: + })) + (begin + ;; Check execution flow + (try! (contract-call? .pyth-governance-v1 check-execution-flow contract-caller (some execution-plan))) + ;; Perform contract-call + (let ((pyth-decoder-contract (get pyth-decoder-contract execution-plan)) + (wormhole-core-contract (get wormhole-core-contract execution-plan)) + (decoded-prices (try! (contract-call? pyth-decoder-contract decode-and-verify-price-feeds price-feed-bytes wormhole-core-contract))) + (fee-info (contract-call? .pyth-governance-v1 get-fee-info)) + (fee-amount (* (len decoded-prices) (* (get mantissa fee-info) (pow u10 (get exponent fee-info)))))) + ;; Charge fee + (unwrap! (stx-transfer? fee-amount tx-sender (get address fee-info)) ERR_BALANCE_INSUFFICIENT) + (ok decoded-prices)))) diff --git a/unit-tests/pyth/oracle.test.ts b/unit-tests/pyth/oracle.test.ts index fa9d04d..88e2115 100644 --- a/unit-tests/pyth/oracle.test.ts +++ b/unit-tests/pyth/oracle.test.ts @@ -4,12 +4,12 @@ import { ParsedTransactionResult } from "@hirosystems/clarinet-sdk"; import { pnauMainnetVaas } from "./fixtures"; import { wormhole } from "../wormhole/helpers"; -const pythOracleContractName = "pyth-oracle-v1"; +const pythOracleContractName = "pyth-oracle-v2"; const pythDecoderPnauContractName = "pyth-pnau-decoder-v1"; const pythStorageContractName = "pyth-store-v1"; const wormholeCoreContractName = "wormhole-core-v1"; -describe("pyth-oracle-v1::decode-and-verify-price-feeds mainnet VAAs", () => { +describe("pyth-oracle-v2::decode-and-verify-price-feeds mainnet VAAs", () => { const accounts = simnet.getAccounts(); const sender = accounts.get("wallet_1")!; diff --git a/unit-tests/pyth/pnau.test.ts b/unit-tests/pyth/pnau.test.ts index 647b62e..aa56ded 100644 --- a/unit-tests/pyth/pnau.test.ts +++ b/unit-tests/pyth/pnau.test.ts @@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it } from "vitest"; import { wormhole } from "../wormhole/helpers"; import { pyth } from "./helpers"; -const pythOracleContractName = "pyth-oracle-v1"; +const pythOracleContractName = "pyth-oracle-v2"; const pythDecoderPnauContractName = "pyth-pnau-decoder-v1"; const pythGovernanceContractName = "pyth-governance-v1"; const pythStorageContractName = "pyth-store-v1"; @@ -788,5 +788,53 @@ describe("pyth-pnau-decoder-v1::decode-and-verify-price-feeds failures", () => { }), ]), ); + + // decode-price-feeds should not be filtering the outdated results + res = simnet.callPublicFn( + pythOracleContractName, + "decode-price-feeds", + [Cl.buffer(pnau), executionPlan], + sender, + ); + expect(res.result).toBeOk( + Cl.list([ + Cl.tuple({ + "price-identifier": Cl.buffer(pyth.BtcPriceIdentifier), + price: Cl.int(actualPricesUpdates.decoded[0].price), + conf: Cl.uint(actualPricesUpdates.decoded[0].conf), + "ema-conf": Cl.uint(actualPricesUpdates.decoded[0].emaConf), + "ema-price": Cl.int(actualPricesUpdates.decoded[0].emaPrice), + expo: Cl.int(actualPricesUpdates.decoded[0].expo), + "prev-publish-time": Cl.uint( + actualPricesUpdates.decoded[0].prevPublishTime, + ), + "publish-time": Cl.uint(actualPricesUpdates.decoded[0].publishTime), + }), + Cl.tuple({ + "price-identifier": Cl.buffer(pyth.StxPriceIdentifier), + price: Cl.int(actualPricesUpdates.decoded[1].price), + conf: Cl.uint(actualPricesUpdates.decoded[1].conf), + "ema-conf": Cl.uint(actualPricesUpdates.decoded[1].emaConf), + "ema-price": Cl.int(actualPricesUpdates.decoded[1].emaPrice), + expo: Cl.int(actualPricesUpdates.decoded[1].expo), + "prev-publish-time": Cl.uint( + actualPricesUpdates.decoded[1].prevPublishTime, + ), + "publish-time": Cl.uint(actualPricesUpdates.decoded[1].publishTime), + }), + Cl.tuple({ + "price-identifier": Cl.buffer(pyth.UsdcPriceIdentifier), + price: Cl.int(actualPricesUpdates.decoded[2].price), + conf: Cl.uint(actualPricesUpdates.decoded[2].conf), + "ema-conf": Cl.uint(actualPricesUpdates.decoded[2].emaConf), + "ema-price": Cl.int(actualPricesUpdates.decoded[2].emaPrice), + expo: Cl.int(actualPricesUpdates.decoded[2].expo), + "prev-publish-time": Cl.uint( + actualPricesUpdates.decoded[2].prevPublishTime, + ), + "publish-time": Cl.uint(actualPricesUpdates.decoded[2].publishTime), + }), + ]), + ); }); }); diff --git a/unit-tests/pyth/ptgm.test.ts b/unit-tests/pyth/ptgm.test.ts index 99d853f..f18bb9e 100644 --- a/unit-tests/pyth/ptgm.test.ts +++ b/unit-tests/pyth/ptgm.test.ts @@ -616,7 +616,7 @@ describe("pyth-governance-v1::update-pyth-oracle-contract", () => { const guardianSet = wormhole.generateGuardianSetKeychain(19); let updateOracleContract = { address: "ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG", - contractName: "pyth-oracle-v2", + contractName: "pyth-oracle-new-version", }; let ptgmVaaPayload = pyth.buildPtgmVaaPayload({ updateOracleContract });