From 9bcff3c0e7472dc15309e3bb55b287ea16a832ea Mon Sep 17 00:00:00 2001 From: devELIOper Date: Wed, 26 Jun 2024 01:46:21 +0530 Subject: [PATCH 1/9] Implemented Math Library for combining pyth prices in solidity using Pyth Structs and Utils --- .../ethereum/sdk/solidity/PriceCombine.sol | 167 ++++++++++++++++++ .../ethereum/sdk/solidity/PythStructs.sol | 2 +- 2 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 target_chains/ethereum/sdk/solidity/PriceCombine.sol diff --git a/target_chains/ethereum/sdk/solidity/PriceCombine.sol b/target_chains/ethereum/sdk/solidity/PriceCombine.sol new file mode 100644 index 0000000000..f1e90da722 --- /dev/null +++ b/target_chains/ethereum/sdk/solidity/PriceCombine.sol @@ -0,0 +1,167 @@ +// PriceCombine.sol +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.0; + +import "./PythStructs.sol"; + +// Constants for working with Pyth's number representation +int32 constant PD_EXPO = -9; +uint64 constant PD_SCALE = 1_000_000_000; +uint64 constant MAX_PD_V_U64 = (1 << 28) - 1; + +// Solidity Library to easily combine 2 Pyth Prices into 1 ( for example SOL:USD/ETH:USD=SOL/ETH). For Rust implementation, refer Pyth Rust SDK https://github.com/pyth-network/pyth-sdk-rs/blob/main/pyth-sdk/src/price.rs +// Based on the Rust implementation, the functions are defined within the `impl Price` block, and they are public methods of the `Price` struct and are as follows `get_price_in_quote`, `div`, `normalize`, `scale_to_exponent` +// Similarly the functions implemented in solidity are `public` and `pure` types. + +library PriceCombine { + /** + * @notice Computes the price in quote currency. + * @param self The price of the base currency. + * @param quote The price of the quote currency. + * @param resultExpo The exponent for the result. + * @return The combined price in the quote currency. + */ + function getPriceInQuote(PythStructs.Price memory self, PythStructs.Price memory quote, int32 resultExpo) public pure returns (PythStructs.Price memory) { + PythStructs.Price memory result = div(self, quote); + // Return zero price so the error can be gracefully handled by the caller + if (result.price == 0 && result.conf == 0) { + return PythStructs.Price({ + price: 0, + conf: 0, + expo: 0, + publishTime: 0 + }); + } + return scaleToExponent(result, resultExpo); + } + + /** + * @notice Divides the price of the base currency by the quote currency price. + * @param self The price of the base currency. + * @param other The price of the quote currency. + * @return The combined price after division. + */ + function div(PythStructs.Price memory self, PythStructs.Price memory other) public pure returns (PythStructs.Price memory) { + PythStructs.Price memory base = normalize(self); + other = normalize(other); + + // If the price of the quote currency is zero, return zero + if (other.price == 0) { + return PythStructs.Price({ + price: 0, + conf: 0, + expo: 0, + publishTime: 0 + }); + } + + // Convert prices to unsigned integers and get their signs + (uint64 basePrice, int64 baseSign) = toUnsigned(base.price); + (uint64 otherPrice, int64 otherSign) = toUnsigned(other.price); + + // Compute the midprice + uint64 midprice = basePrice * PD_SCALE / otherPrice; + int32 midpriceExpo = base.expo - other.expo + PD_EXPO; + + // Compute the confidence interval + uint64 otherConfidencePct = other.conf * PD_SCALE / otherPrice; + uint128 conf = (base.conf * PD_SCALE / otherPrice) + (otherConfidencePct * midprice) / PD_SCALE; + + // Check for overflow and return the result + if (conf < type(uint64).max) { + return PythStructs.Price( + int64(int64(midprice) * baseSign * otherSign), + uint64(conf), + midpriceExpo, + self.publishTime < other.publishTime ? self.publishTime : other.publishTime + ); + } else { + // Return zero price if there's an overflow + return PythStructs.Price({ + price: 0, + conf: 0, + expo: 0, + publishTime: 0 + }); + } + } + + /** + * @notice Normalizes the price and confidence to be within acceptable range. + * @param self The price structure to normalize. + * @return The normalized price structure. + */ + function normalize(PythStructs.Price memory self) public pure returns (PythStructs.Price memory) { + (uint64 price, int64 sign) = toUnsigned(self.price); + uint64 conf = self.conf; + int32 expo = self.expo; + + // Adjust the price and confidence if they are too large + while (price > MAX_PD_V_U64 || conf > MAX_PD_V_U64) { + price = price / 10; + conf = conf / 10; + expo = expo + 1; + } + + return PythStructs.Price({ + price: int64(price) * sign, + conf: conf, + expo: expo, + publishTime: self.publishTime + }); + } + + /** + * @notice Scales the price to the target exponent. + * @param self The price structure to scale. + * @param targetExpo The target exponent. + * @return The scaled price structure. + */ + function scaleToExponent(PythStructs.Price memory self, int32 targetExpo) public pure returns (PythStructs.Price memory) { + int32 delta = targetExpo - self.expo; + int64 price = self.price; + uint64 conf = self.conf; + + // Adjust the price and confidence based on the exponent difference + if (delta >= 0) { + while (delta > 0 && (price != 0 || conf != 0)) { + price = price / 10; + conf = conf / 10; + delta = delta - 1; + } + return PythStructs.Price({ + price: price, + conf: conf, + expo: targetExpo, + publishTime: self.publishTime + }); + } else { + while (delta < 0) { + price = price * 10; + conf = conf * 10; + delta = delta + 1; + } + return PythStructs.Price({ + price: price, + conf: conf, + expo: targetExpo, + publishTime: self.publishTime + }); + } + } + + /** + * @notice Converts a signed integer to an unsigned integer and a sign bit. + * @param x here is the signed integer. + * @return The unsigned integer and sign bit. + */ + function toUnsigned(int64 x) public pure returns (uint64, int64) { + if (x == type(int64).min) { + return (uint64(type(int64).max) + 1, -1); + } else if (x < 0) { + return (uint64(-x), -1); + } else { + return (uint64(x), 1); + } + } +} diff --git a/target_chains/ethereum/sdk/solidity/PythStructs.sol b/target_chains/ethereum/sdk/solidity/PythStructs.sol index b3d2ee2c6a..9696af78bf 100644 --- a/target_chains/ethereum/sdk/solidity/PythStructs.sol +++ b/target_chains/ethereum/sdk/solidity/PythStructs.sol @@ -30,4 +30,4 @@ contract PythStructs { // Latest available exponentially-weighted moving average price Price emaPrice; } -} +} \ No newline at end of file From 4ccc1dd5b9188afd6a8aa6e906a2860dfe3a7326 Mon Sep 17 00:00:00 2001 From: devELIOper Date: Wed, 26 Jun 2024 01:47:17 +0530 Subject: [PATCH 2/9] Implemented test contract to test library functions in Remix IDE --- .../sdk/solidity/PriceCombineTest.sol | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 target_chains/ethereum/sdk/solidity/PriceCombineTest.sol diff --git a/target_chains/ethereum/sdk/solidity/PriceCombineTest.sol b/target_chains/ethereum/sdk/solidity/PriceCombineTest.sol new file mode 100644 index 0000000000..d984f5a856 --- /dev/null +++ b/target_chains/ethereum/sdk/solidity/PriceCombineTest.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.0; + +import "./PythStructs.sol"; +import "./PriceCombine.sol"; + +// This contract is used to test the library functions and tested in Remix IDE. All ABIs are present in the /abis folder +contract PriceCombineTest { + using PriceCombine for PythStructs.Price; + + /** + * @notice Test the getPriceInQuote function + * @param basePrice The price of the base currency (example: SOL/USD) 13913000000 (represents the current SOL/USD $139.13 with 8 decimal places) + * @param baseConf The confidence interval of the base currency + * @param baseExpo The exponent of the base currency (here: -8 -> 8 decimal units) indicates price is scaled by 10^-8 + * @param basePublishTime The publish time of the base currency (UNIX timestamp) + * @param quotePrice The price of the quote currency (example: ETH/USD) 341853000000 (represents the current ETH/USD $3418.53 with 8 decimal places) + * @param quoteConf The confidence interval of the quote currency + * @param quoteExpo The exponent of the quote currency (here: -8 -> 8 decimal units) indicates price is scaled by 10^-8 + * @param quotePublishTime The publish time of the quote currency (UNIX timestamp) + * @param resultExpo The desired exponent for the result (here: -8) + * @return The price, confidence interval, exponent, and publish time of the resulting price + */ + function testGetPriceInQuote(int64 basePrice, uint64 baseConf, int32 baseExpo, uint basePublishTime, + int64 quotePrice, uint64 quoteConf, int32 quoteExpo, uint quotePublishTime, + int32 resultExpo) public pure returns (int64, uint64, int32, uint) { + PythStructs.Price memory base = PythStructs.Price(basePrice, baseConf, baseExpo, basePublishTime); + PythStructs.Price memory quote = PythStructs.Price(quotePrice, quoteConf, quoteExpo, quotePublishTime); + PythStructs.Price memory result = base.getPriceInQuote(quote, resultExpo); + return (result.price, result.conf, result.expo, result.publishTime); + } + + // Add more test functions as needed +} From 24a60ec1beb7e23b889c6088a2e6bc1ead48c9f3 Mon Sep 17 00:00:00 2001 From: devELIOper Date: Wed, 26 Jun 2024 01:49:56 +0530 Subject: [PATCH 3/9] added ABIs from compiled smart contracts in Remix IDE --- .../sdk/solidity/abis/PriceCombine.json | 342 ++++++++++++++++++ .../sdk/solidity/abis/PriceCombineTest.json | 76 ++++ .../sdk/solidity/abis/PythStructs.json | 1 + 3 files changed, 419 insertions(+) create mode 100644 target_chains/ethereum/sdk/solidity/abis/PriceCombine.json create mode 100644 target_chains/ethereum/sdk/solidity/abis/PriceCombineTest.json create mode 100644 target_chains/ethereum/sdk/solidity/abis/PythStructs.json diff --git a/target_chains/ethereum/sdk/solidity/abis/PriceCombine.json b/target_chains/ethereum/sdk/solidity/abis/PriceCombine.json new file mode 100644 index 0000000000..49ce577a55 --- /dev/null +++ b/target_chains/ethereum/sdk/solidity/abis/PriceCombine.json @@ -0,0 +1,342 @@ +[ + { + "inputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "self", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "other", + "type": "tuple" + } + ], + "name": "div", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "self", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "quote", + "type": "tuple" + }, + { + "internalType": "int32", + "name": "resultExpo", + "type": "int32" + } + ], + "name": "getPriceInQuote", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "self", + "type": "tuple" + } + ], + "name": "normalize", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "self", + "type": "tuple" + }, + { + "internalType": "int32", + "name": "targetExpo", + "type": "int32" + } + ], + "name": "scaleToExponent", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int64", + "name": "x", + "type": "int64" + } + ], + "name": "toUnsigned", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + }, + { + "internalType": "int64", + "name": "", + "type": "int64" + } + ], + "stateMutability": "pure", + "type": "function" + } +] \ No newline at end of file diff --git a/target_chains/ethereum/sdk/solidity/abis/PriceCombineTest.json b/target_chains/ethereum/sdk/solidity/abis/PriceCombineTest.json new file mode 100644 index 0000000000..1ed43ff648 --- /dev/null +++ b/target_chains/ethereum/sdk/solidity/abis/PriceCombineTest.json @@ -0,0 +1,76 @@ +[ + { + "inputs": [ + { + "internalType": "int64", + "name": "basePrice", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "baseConf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "baseExpo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "basePublishTime", + "type": "uint256" + }, + { + "internalType": "int64", + "name": "quotePrice", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "quoteConf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "quoteExpo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "quotePublishTime", + "type": "uint256" + }, + { + "internalType": "int32", + "name": "resultExpo", + "type": "int32" + } + ], + "name": "testGetPriceInQuote", + "outputs": [ + { + "internalType": "int64", + "name": "", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + } +] \ No newline at end of file diff --git a/target_chains/ethereum/sdk/solidity/abis/PythStructs.json b/target_chains/ethereum/sdk/solidity/abis/PythStructs.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/target_chains/ethereum/sdk/solidity/abis/PythStructs.json @@ -0,0 +1 @@ +[] \ No newline at end of file From ed1c3fed182379b730193870c8508ad40a311306 Mon Sep 17 00:00:00 2001 From: devELIOper Date: Sun, 30 Jun 2024 23:19:08 +0530 Subject: [PATCH 4/9] added methods and test to parse pyth benchmark prices on aptos --- .../aptos/contracts/sources/pyth.move | 292 +++++++++++++++++- 1 file changed, 290 insertions(+), 2 deletions(-) diff --git a/target_chains/aptos/contracts/sources/pyth.move b/target_chains/aptos/contracts/sources/pyth.move index a831643061..66a3c129c8 100644 --- a/target_chains/aptos/contracts/sources/pyth.move +++ b/target_chains/aptos/contracts/sources/pyth.move @@ -30,7 +30,6 @@ module pyth::pyth { const PYTHNET_ACCUMULATOR_UPDATE_MAGIC: u64 = 1347305813; const ACCUMULATOR_UPDATE_WORMHOLE_VERIFICATION_MAGIC: u64 = 1096111958; - // ----------------------------------------------------------------------------- // Initialisation functions @@ -520,6 +519,127 @@ module pyth::pyth { }; state::get_base_update_fee() * total_updates } + + + /// Parse Benchmark Prices Method + + /// Parses and validates price feeds within the specified publish time range. + fun parse_and_validate_price_feeds( + price_infos: &vector, + requested_price_ids: vector>, + min_publish_time: u64, + max_publish_time: u64 + ): vector { + // Initialize vectors to store parsed price feeds and price IDs + let valid_price_feeds = vector::empty(); + let valid_price_ids = vector::empty>(); + + // Iterate through the price information to filter and validate based on publish times + let i = 0; + while (i < vector::length(price_infos)) { + let price_info = vector::borrow(price_infos, i); + let price_feed = price_info::get_price_feed(price_info); + let price: price::Price = price_feed::get_price(price_feed); + let timestamp = price::get_timestamp(&price); + + // Check if the price feed is within the specified publish time range + if (timestamp >= min_publish_time && timestamp <= max_publish_time) { + let price_id: &price_identifier::PriceIdentifier = price_feed::get_price_identifier(price_feed); + let price_id_bytes = price_identifier::get_bytes(price_id); + vector::push_back(&mut valid_price_ids, price_id_bytes); + vector::push_back(&mut valid_price_feeds, *price_feed); + }; + i = i + 1; + }; + + // Ensure all requested price IDs have corresponding valid updates + let k = 0; + while (k < vector::length(&requested_price_ids)) { + let requested_price_id = vector::borrow(&requested_price_ids, k); + let is_found = false; + + // Check if the requested price ID is in the valid price IDs + let j = 0; + while (j < vector::length(&valid_price_ids)) { + let valid_price_id = vector::borrow(&valid_price_ids, j); + if (requested_price_id == valid_price_id) { + is_found = true; + break + }; + j = j + 1; + }; + + // Abort if any requested price ID does not have a valid update + if (!is_found) { + abort error::unknown_price_feed() // Replace with a more suitable error if needed + }; + k = k + 1; + }; + + return valid_price_feeds + } + + /// Parses a single VAA and returns a vector of price feeds within the specified publish time range. + fun parse_price_feed_updates_from_vaa( + vaa: vector, + requested_price_ids: vector>, + min_publish_time: u64, + max_publish_time: u64 + ): vector { + let cur = cursor::init(vaa); + let header: u64 = deserialize::deserialize_u32(&mut cur); + if (header == PYTHNET_ACCUMULATOR_UPDATE_MAGIC) { + let price_infos = parse_and_verify_accumulator_message(&mut cur); + cursor::rest(cur); + return parse_and_validate_price_feeds(&price_infos, requested_price_ids, min_publish_time, max_publish_time) + } else { + let vaa = vaa::parse_and_verify(vaa); + verify_data_source(&vaa); + let price_infos = batch_price_attestation::destroy(batch_price_attestation::deserialize(vaa::destroy(vaa))); + cursor::rest(cur); + return parse_and_validate_price_feeds(&price_infos, requested_price_ids, min_publish_time, max_publish_time) + } + } + + /// Public function to parse multiple price feed updates from VAA data. + public fun parse_price_feed_updates( + update_data: vector>, + requested_price_ids: vector>, + min_publish_time: u64, + max_publish_time: u64, + fee: Coin + ): vector { + // Validate and deposit the update fee + let update_fee = get_update_fee(&update_data); + assert!(update_fee <= coin::value(&fee), error::insufficient_fee()); + coin::deposit(@pyth, fee); + let pyth_balance = coin::balance(@pyth); + assert!(pyth_balance >= update_fee, error::insufficient_fee()); + + // Initialize a vector to store all valid price feeds + let all_valid_price_feeds = vector::empty(); + + // Iterate through the update_data vector + let i = 0; + while (i < vector::length(&update_data)) { + // Parse a single VAA and get its valid price feeds + let single_vaa = vector::borrow(&update_data, i); + let valid_price_feeds = parse_price_feed_updates_from_vaa(*single_vaa, requested_price_ids, min_publish_time, max_publish_time); + + // Add each valid price feed to the all_valid_price_feeds vector + let j = 0; + while (j < vector::length(&valid_price_feeds)) { + let price_feed = vector::borrow(&valid_price_feeds, j); + vector::push_back(&mut all_valid_price_feeds, *price_feed); + j = j + 1; + }; + + i = i + 1; + }; + + all_valid_price_feeds + } + } // ----------------------------------------------------------------------------- @@ -1430,4 +1550,172 @@ module pyth::pyth_test { cleanup_test(burn_capability, mint_capability); } -} + + // Test case for successful parsing of price feed updates + #[test(aptos_framework = @aptos_framework)] + fun test_parse_price_feed_updates_success(aptos_framework: &signer) { + let update_fee = 50; + let initial_balance = 100; + let (burn_capability, mint_capability, coins) = setup_test(aptos_framework, 500, 1, + x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", + vector[/* Add valid DataSource objects here */], + update_fee, + initial_balance); + + let update_data = vector[ + /* Add actual VAA bytes here for testing */ + ]; + let price_ids = vector[ + x"c6c75c89f14810ec1c54c03ab8f1864a4c4032791f05747f560faec380a695d1", + x"3b9551a68d01d954d6387aff4df1529027ffb2fee413082e509feb29cc4904fe", + x"33832fad6e36eb05a8972fe5f219b27b5b2bb2230a79ce79beb4c5c5e7ecc76d", + x"21a28b4c6619968bd8c20e95b0aaed7df2187fd310275347e0376a2cd7427db8", + ]; + let min_publish_time: u64 = 1663074345; + let max_publish_time: u64 = 1663680750; + + let test_price_feeds: vector = pyth::parse_price_feed_updates(update_data, price_ids, min_publish_time, max_publish_time, coins); + + assert!(vector::length(&test_price_feeds) > 0, 1); + // Add further assertions based on expected results + + cleanup_test(burn_capability, mint_capability); + } + + // Test case for insufficient fee during parsing of price feed updates + #[test(aptos_framework = @aptos_framework)] + #[expected_failure(abort_code = 65542, location = pyth::pyth)] + fun test_parse_price_feed_updates_insufficient_fee(aptos_framework: &signer) { + let update_fee = 50; + let initial_balance = 20; + let (burn_capability, mint_capability, coins) = setup_test(aptos_framework, 500, 1, + x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", + vector[/* Add valid DataSource objects here */], + update_fee, + initial_balance); + + let update_data = vector[ + /* Add actual VAA bytes here for testing */ + ]; + let price_ids = vector[ + x"c6c75c89f14810ec1c54c03ab8f1864a4c4032791f05747f560faec380a695d1", + x"3b9551a68d01d954d6387aff4df1529027ffb2fee413082e509feb29cc4904fe", + x"33832fad6e36eb05a8972fe5f219b27b5b2bb2230a79ce79beb4c5c5e7ecc76d", + x"21a28b4c6619968bd8c20e95b0aaed7df2187fd310275347e0376a2cd7427db8", + ]; + let min_publish_time: u64 = 1663074345; + let max_publish_time: u64 = 1663680750; + + pyth::parse_price_feed_updates(update_data, price_ids, min_publish_time, max_publish_time, coins); + + cleanup_test(burn_capability, mint_capability); + } + + // Test case for corrupt VAA during parsing of price feed updates + #[test(aptos_framework = @aptos_framework)] + #[expected_failure(abort_code = 6, location = wormhole::vaa)] + fun test_parse_price_feed_updates_corrupt_vaa(aptos_framework: &signer) { + let (burn_capability, mint_capability, coins) = setup_test(aptos_framework, 500, 1, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", vector[], 50, 100); + + let corrupt_vaa = x"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"; + let price_ids = vector[ + x"c6c75c89f14810ec1c54c03ab8f1864a4c4032791f05747f560faec380a695d1", + x"3b9551a68d01d954d6387aff4df1529027ffb2fee413082e509feb29cc4904fe", + x"33832fad6e36eb05a8972fe5f219b27b5b2bb2230a79ce79beb4c5c5e7ecc76d", + x"21a28b4c6619968bd8c20e95b0aaed7df2187fd310275347e0376a2cd7427db8", + ]; + let min_publish_time: u64 = 1663074345; + let max_publish_time: u64 = 1663680750; + + pyth::parse_price_feed_updates(vector[corrupt_vaa], price_ids, min_publish_time, max_publish_time, coins); + + cleanup_test(burn_capability, mint_capability); + } + + // Test case for invalid data source during parsing of price feed updates + #[test(aptos_framework = @aptos_framework)] + #[expected_failure(abort_code = 65539, location = pyth::pyth)] + fun test_parse_price_feed_updates_invalid_data_source(aptos_framework: &signer) { + let update_data = vector[ + /* Add actual VAA bytes here for testing */ + ]; + let price_ids = vector[ + x"c6c75c89f14810ec1c54c03ab8f1864a4c4032791f05747f560faec380a695d1", + x"3b9551a68d01d954d6387aff4df1529027ffb2fee413082e509feb29cc4904fe", + x"33832fad6e36eb05a8972fe5f219b27b5b2bb2230a79ce79beb4c5c5e7ecc76d", + x"21a28b4c6619968bd8c20e95b0aaed7df2187fd310275347e0376a2cd7427db8", + ]; + let min_publish_time: u64 = 1663074345; + let max_publish_time: u64 = 1663680750; + + let data_sources = vector[ + DataSource { id: 4, address: external_address::from_bytes(x"0000000000000000000000000000000000000000000000000000000000007742") }, + DataSource { id: 5, address: external_address::from_bytes(x"0000000000000000000000000000000000000000000000000000000000007637") } + ]; + let (burn_capability, mint_capability, coins) = setup_test(aptos_framework, 500, 1, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, 50, 100); + + pyth::parse_price_feed_updates(update_data, price_ids, min_publish_time, max_publish_time, coins); + + cleanup_test(burn_capability, mint_capability); + } + + // Test case for invalid price ID during parsing of price feed updates + #[test(aptos_framework = @aptos_framework)] + #[expected_failure(abort_code = 393224, location = pyth::pyth)] + fun test_parse_price_feed_updates_invalid_price_id(aptos_framework: &signer) { + let update_fee = 50; + let initial_balance = 100; + let (burn_capability, mint_capability, coins) = setup_test(aptos_framework, 500, 1, + x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", + vector[/* Add valid DataSource objects here */], + update_fee, + initial_balance); + + let update_data = vector[ + /* Add actual VAA bytes here for testing */ + ]; + let price_ids = vector[ + x"c6c75c89f14810ec1c54c03ab8f1864a4c4032791f05747f560faec380a695d2", // invalid price id + x"3b9551a68d01d954d6387aff4df1529027ffb2fee413082e509feb29cc4904fe", + x"33832fad6e36eb05a8972fe5f219b27b5b2bb2230a79ce79beb4c5c5e7ecc76d", + x"21a28b4c6619968bd8c20e95b0aaed7df2187fd310275347e0376a2cd7427db8", + ]; + let min_publish_time: u64 = 1663074345; + let max_publish_time: u64 = 1663680750; + + pyth::parse_price_feed_updates(update_data, price_ids, min_publish_time, max_publish_time, coins); + + cleanup_test(burn_capability, mint_capability); + } + + // Test case for invalid publish times during parsing of price feed updates + #[test(aptos_framework = @aptos_framework)] + #[expected_failure(abort_code = 393224, location = pyth::pyth)] + fun test_parse_price_feed_updates_invalid_publish_times(aptos_framework: &signer) { + let update_fee = 50; + let initial_balance = 100; + let (burn_capability, mint_capability, coins) = setup_test(aptos_framework, 500, 1, + x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", + vector[/* Add valid DataSource objects here */], + update_fee, + initial_balance); + + let update_data = vector[ + /* Add actual VAA bytes here for testing */ + ]; + let price_ids = vector[ + x"c6c75c89f14810ec1c54c03ab8f1864a4c4032791f05747f560faec380a695d1", + x"3b9551a68d01d954d6387aff4df1529027ffb2fee413082e509feb29cc4904fe", + x"33832fad6e36eb05a8972fe5f219b27b5b2bb2230a79ce79beb4c5c5e7ecc76d", + x"21a28b4c6619968bd8c20e95b0aaed7df2187fd310275347e0376a2cd7427db8", + ]; + // invalid publish times: max_publish_time is less than min_publish_time + let min_publish_time: u64 = 1663680750; + let max_publish_time: u64 = 1663074345; + + pyth::parse_price_feed_updates(update_data, price_ids, min_publish_time, max_publish_time, coins); + + cleanup_test(burn_capability, mint_capability); + } + +} \ No newline at end of file From 5ee038ad735cae491d8725099b57bcac21829b8d Mon Sep 17 00:00:00 2001 From: devELIOper Date: Mon, 1 Jul 2024 01:44:26 +0530 Subject: [PATCH 5/9] compilation errors added price update v2 functions in lib.rs --- .../programs/pyth-solana-receiver/src/lib.rs | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs index 868844bedd..6491e9805e 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs @@ -254,6 +254,49 @@ pub mod pyth_solana_receiver { pub fn reclaim_rent(_ctx: Context) -> Result<()> { Ok(()) } + + // New function to initialize a PriceUpdateV2 account without verifications (for testing) + pub fn initialize_price_update_v2( + ctx: Context, + price: i64, + conf: u64, + exponent: i32, + feed_id: [u8; 32], + publish_time: u64, + prev_publish_time: u64, + ) -> Result<()> { + let price_update_account = &mut ctx.accounts.price_update_account; + price_update_account.price = price; + price_update_account.conf = conf; + price_update_account.exponent = exponent; + price_update_account.feed_id = feed_id; + price_update_account.publish_time = publish_time; + price_update_account.prev_publish_time = prev_publish_time; + price_update_account.is_initialized = true; + Ok(()) + } + + // New function to update a PriceUpdateV2 account without verifications (for testing) + pub fn update_price_update_v2( + ctx: Context, + price: i64, + conf: u64, + exponent: i32, + feed_id: [u8; 32], + publish_time: u64, + prev_publish_time: u64, + ) -> Result<()> { + let price_update_account = &mut ctx.accounts.price_update_account; + require!(price_update_account.is_initialized, ReceiverError::UninitializedAccount); + + price_update_account.price = price; + price_update_account.conf = conf; + price_update_account.exponent = exponent; + price_update_account.feed_id = feed_id; + price_update_account.publish_time = publish_time; + price_update_account.prev_publish_time = prev_publish_time; + Ok(()) + } } #[derive(Accounts)] @@ -340,6 +383,24 @@ pub struct ReclaimRent<'info> { pub price_update_account: Account<'info, PriceUpdateV2>, } +// New context for initializing PriceUpdateV2 without verifications +#[derive(Accounts)] +pub struct InitializePriceUpdateV2<'info> { + #[account(init, payer = user, space = PriceUpdateV2::LEN)] + pub price_update_account: Account<'info, PriceUpdateV2>, + #[account(mut)] + pub user: Signer<'info>, + pub system_program: Program<'info, System>, +} + +// New context for updating PriceUpdateV2 without verifications +#[derive(Accounts)] +pub struct UpdatePriceUpdateV2<'info> { + #[account(mut)] + pub price_update_account: Account<'info, PriceUpdateV2>, + pub user: Signer<'info>, +} + fn deserialize_guardian_set_checked( account_info: &AccountInfo<'_>, wormhole: &Pubkey, From 49e2901777ede6992e46f47720f6d3f8275c2cb5 Mon Sep 17 00:00:00 2001 From: devELIOper Date: Mon, 1 Jul 2024 01:45:12 +0530 Subject: [PATCH 6/9] implemented instruction to update price v2 --- .../programs/pyth-solana-receiver/src/sdk.rs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/sdk.rs b/target_chains/solana/programs/pyth-solana-receiver/src/sdk.rs index 1d78484ccc..7525fa7d3e 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/sdk.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/sdk.rs @@ -302,6 +302,68 @@ impl instruction::ReclaimRent { } } +impl instruction::InitializePriceUpdateV2 { + pub fn populate( + payer: &Pubkey, + price: i64, + conf: u64, + exponent: i32, + feed_id: [u8; 32], + publish_time: u64, + prev_publish_time: u64, + ) -> Instruction { + Instruction { + program_id: ID, + accounts: accounts::InitializePriceUpdateV2 { + price_update_account: Pubkey::new_unique(), + user: *payer, + system_program: system_program::ID, + } + .to_account_metas(None), + data: instruction::InitializePriceUpdateV2 { + price, + conf, + exponent, + feed_id, + publish_time, + prev_publish_time, + } + .data(), + } + } +} + +impl instruction::UpdatePriceUpdateV2 { + pub fn populate( + payer: &Pubkey, + price_update_account: Pubkey, + price: i64, + conf: u64, + exponent: i32, + feed_id: [u8; 32], + publish_time: u64, + prev_publish_time: u64, + ) -> Instruction { + Instruction { + program_id: ID, + accounts: accounts::UpdatePriceUpdateV2 { + price_update_account, + user: *payer, + } + .to_account_metas(None), + data: instruction::UpdatePriceUpdateV2 { + price, + conf, + exponent, + feed_id, + publish_time, + prev_publish_time, + } + .data(), + } + } +} + pub fn get_guardian_set_address(wormhole_address: Pubkey, guardian_set_index: u32) -> Pubkey { Pubkey::find_program_address( &[ From 4757755e138b0bf0e542c86cdf48a8f9e8721f29 Mon Sep 17 00:00:00 2001 From: devELIOper Date: Mon, 1 Jul 2024 01:45:41 +0530 Subject: [PATCH 7/9] test to check price update stub --- .../tests/test_stub_price_updates.rs | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 target_chains/solana/programs/pyth-solana-receiver/tests/test_stub_price_updates.rs diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_stub_price_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_stub_price_updates.rs new file mode 100644 index 0000000000..00420c06c3 --- /dev/null +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_stub_price_updates.rs @@ -0,0 +1,136 @@ +use anchor_lang::prelude::*; +use pyth_solana_receiver::pyth_solana_receiver::{initialize_price_update_v2, update_price_update_v2, PriceUpdateV2}; +use solana_program_test::*; +use solana_sdk::{ + account::Account as SolanaAccount, signature::Keypair, signer::Signer, transaction::Transaction, +}; + +#[tokio::test] +async fn test_initialize_price_update() { + let program_id = Pubkey::new_unique(); + let mut program_test = ProgramTest::new( + "pyth_solana_receiver", + program_id, + processor!(pyth_solana_receiver::pyth_solana_receiver::processor), + ); + + let price_update_keypair = Keypair::new(); + let price_update_account = price_update_keypair.pubkey(); + + program_test.add_account( + price_update_account, + SolanaAccount::new(1_000_000, PriceUpdateV2::LEN, &program_id), + ); + + let (mut banks_client, payer, recent_blockhash) = program_test.start().await; + + let price_update = PriceUpdateV2 { + price: 100, + conf: 10, + exponent: -2, + feed_id: [0u8; 32], + publish_time: 1_624_099_200, + prev_publish_time: 1_624_098_200, + is_initialized: false, + }; + + let init_ix = initialize_price_update_v2( + price_update_account, + price_update.price, + price_update.conf, + price_update.exponent, + price_update.feed_id, + price_update.publish_time, + price_update.prev_publish_time, + ); + + let mut transaction = Transaction::new_with_payer(&[init_ix], Some(&payer.pubkey())); + transaction.sign(&[&payer, &price_update_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + let account = banks_client + .get_account(price_update_account) + .await + .unwrap() + .unwrap(); + let price_update_data = PriceUpdateV2::try_deserialize(&mut account.data.as_slice()).unwrap(); + + assert_eq!(price_update_data, price_update); +} + +#[tokio::test] +async fn test_update_price_update() { + let program_id = Pubkey::new_unique(); + let mut program_test = ProgramTest::new( + "pyth_solana_receiver", + program_id, + processor!(pyth_solana_receiver::pyth_solana_receiver::processor), + ); + + let price_update_keypair = Keypair::new(); + let price_update_account = price_update_keypair.pubkey(); + + program_test.add_account( + price_update_account, + SolanaAccount::new(1_000_000, PriceUpdateV2::LEN, &program_id), + ); + + let (mut banks_client, payer, recent_blockhash) = program_test.start().await; + + let initial_price_update = PriceUpdateV2 { + price: 100, + conf: 10, + exponent: -2, + feed_id: [0u8; 32], + publish_time: 1_624_099_200, + prev_publish_time: 1_624_098_200, + is_initialized: false, + }; + + let init_ix = initialize_price_update_v2( + price_update_account, + initial_price_update.price, + initial_price_update.conf, + initial_price_update.exponent, + initial_price_update.feed_id, + initial_price_update.publish_time, + initial_price_update.prev_publish_time, + ); + + let mut transaction = Transaction::new_with_payer(&[init_ix], Some(&payer.pubkey())); + transaction.sign(&[&payer, &price_update_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + let updated_price_update = PriceUpdateV2 { + price: 200, + conf: 20, + exponent: -3, + feed_id: [1u8; 32], + publish_time: 1_624_199_200, + prev_publish_time: 1_624_198_200, + is_initialized: true, + }; + + let update_ix = update_price_update_v2( + price_update_account, + updated_price_update.price, + updated_price_update.conf, + updated_price_update.exponent, + updated_price_update.feed_id, + updated_price_update.publish_time, + updated_price_update.prev_publish_time, + ); + + let mut transaction = Transaction::new_with_payer(&[update_ix], Some(&payer.pubkey())); + transaction.sign(&[&payer, &price_update_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + let account = banks_client + .get_account(price_update_account) + .await + .unwrap() + .unwrap(); + let price_update_data = PriceUpdateV2::try_deserialize(&mut account.data.as_slice()).unwrap(); + + assert_eq!(price_update_data, updated_price_update); +} From 8e9d8b39715b6154bfa2318ec745f74edb7fd701 Mon Sep 17 00:00:00 2001 From: devELIOper Date: Mon, 1 Jul 2024 01:46:16 +0530 Subject: [PATCH 8/9] updated config: issue with compile due to incomatible rust crates --- target_chains/solana/Cargo.lock | 70 +++++++++++++++++-- .../pyth-solana-receiver/.cargo/config.toml | 2 + .../programs/pyth-solana-receiver/Cargo.toml | 2 + 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 target_chains/solana/programs/pyth-solana-receiver/.cargo/config.toml diff --git a/target_chains/solana/Cargo.lock b/target_chains/solana/Cargo.lock index 7def373edd..858b0791b8 100644 --- a/target_chains/solana/Cargo.lock +++ b/target_chains/solana/Cargo.lock @@ -1266,14 +1266,38 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.79", + "quote 1.0.33", + "strsim 0.10.0", + "syn 1.0.107", ] [[package]] @@ -1290,13 +1314,24 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote 1.0.33", + "syn 1.0.107", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote 1.0.33", "syn 2.0.39", ] @@ -3074,6 +3109,7 @@ dependencies = [ "pyth-solana-receiver-sdk", "pythnet-sdk", "rand 0.8.5", + "serde_with 1.14.0", "serde_wormhole", "solana-program", "solana-sdk", @@ -3790,6 +3826,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros 1.5.2", +] + [[package]] name = "serde_with" version = "2.3.3" @@ -3797,7 +3843,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" dependencies = [ "serde", - "serde_with_macros", + "serde_with_macros 2.3.3", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling 0.13.4", + "proc-macro2 1.0.79", + "quote 1.0.33", + "syn 1.0.107", ] [[package]] @@ -3806,7 +3864,7 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2 1.0.79", "quote 1.0.33", "syn 2.0.39", @@ -4695,7 +4753,7 @@ dependencies = [ "serde_bytes", "serde_derive", "serde_json", - "serde_with", + "serde_with 2.3.3", "sha2 0.10.6", "sha3 0.10.6", "solana-frozen-abi", diff --git a/target_chains/solana/programs/pyth-solana-receiver/.cargo/config.toml b/target_chains/solana/programs/pyth-solana-receiver/.cargo/config.toml new file mode 100644 index 0000000000..a14129b9dd --- /dev/null +++ b/target_chains/solana/programs/pyth-solana-receiver/.cargo/config.toml @@ -0,0 +1,2 @@ +[unstable] +namespaced-features = true diff --git a/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml b/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml index 10e8aa8836..5376711d86 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml +++ b/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml @@ -24,6 +24,7 @@ wormhole-core-bridge-solana = {workspace = true} wormhole-raw-vaas = {version = "0.1.3", features = ["ruint", "on-chain"], default-features = false } pyth-solana-receiver-sdk = { path = "../../pyth_solana_receiver_sdk"} rand = "0.8.5" +serde_with = "3.8.1" [dev-dependencies] solana-sdk = { workspace = true } @@ -32,3 +33,4 @@ program-simulator = { path = "../../program_simulator" } wormhole-vaas-serde = { workspace = true } serde_wormhole = { workspace = true } common-test-utils = { path = "../../common_test_utils" } +# pyth_solana_receiver = { path = "../pyth-solana-receiver/src/programs/pyth_solana_receiver" } # Update this line From 85ba28dec07c63d0092da0a87e718f16d4516135 Mon Sep 17 00:00:00 2001 From: devELIOper Date: Mon, 1 Jul 2024 20:47:56 +0530 Subject: [PATCH 9/9] updated dependencies - still facing same error --- target_chains/solana/Cargo.lock | 71 ++----------------- .../programs/pyth-solana-receiver/Cargo.toml | 6 +- 2 files changed, 10 insertions(+), 67 deletions(-) diff --git a/target_chains/solana/Cargo.lock b/target_chains/solana/Cargo.lock index 858b0791b8..a7696515ce 100644 --- a/target_chains/solana/Cargo.lock +++ b/target_chains/solana/Cargo.lock @@ -1266,38 +1266,14 @@ dependencies = [ "syn 1.0.107", ] -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core 0.20.3", - "darling_macro 0.20.3", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2 1.0.79", - "quote 1.0.33", - "strsim 0.10.0", - "syn 1.0.107", + "darling_core", + "darling_macro", ] [[package]] @@ -1314,24 +1290,13 @@ dependencies = [ "syn 2.0.39", ] -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core 0.13.4", - "quote 1.0.33", - "syn 1.0.107", -] - [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core 0.20.3", + "darling_core", "quote 1.0.33", "syn 2.0.39", ] @@ -3109,7 +3074,7 @@ dependencies = [ "pyth-solana-receiver-sdk", "pythnet-sdk", "rand 0.8.5", - "serde_with 1.14.0", + "serde_with", "serde_wormhole", "solana-program", "solana-sdk", @@ -3826,16 +3791,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" -dependencies = [ - "serde", - "serde_with_macros 1.5.2", -] - [[package]] name = "serde_with" version = "2.3.3" @@ -3843,19 +3798,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" dependencies = [ "serde", - "serde_with_macros 2.3.3", -] - -[[package]] -name = "serde_with_macros" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" -dependencies = [ - "darling 0.13.4", - "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 1.0.107", + "serde_with_macros", ] [[package]] @@ -3864,7 +3807,7 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ - "darling 0.20.3", + "darling", "proc-macro2 1.0.79", "quote 1.0.33", "syn 2.0.39", @@ -4753,7 +4696,7 @@ dependencies = [ "serde_bytes", "serde_derive", "serde_json", - "serde_with 2.3.3", + "serde_with", "sha2 0.10.6", "sha3 0.10.6", "solana-frozen-abi", diff --git a/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml b/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml index 5376711d86..87b0e308e1 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml +++ b/target_chains/solana/programs/pyth-solana-receiver/Cargo.toml @@ -24,13 +24,13 @@ wormhole-core-bridge-solana = {workspace = true} wormhole-raw-vaas = {version = "0.1.3", features = ["ruint", "on-chain"], default-features = false } pyth-solana-receiver-sdk = { path = "../../pyth_solana_receiver_sdk"} rand = "0.8.5" -serde_with = "3.8.1" +serde_with = { version = "2.3.3", default-features = false } [dev-dependencies] -solana-sdk = { workspace = true } +solana-sdk = { workspace = true } tokio = "1.14.1" program-simulator = { path = "../../program_simulator" } wormhole-vaas-serde = { workspace = true } serde_wormhole = { workspace = true } common-test-utils = { path = "../../common_test_utils" } -# pyth_solana_receiver = { path = "../pyth-solana-receiver/src/programs/pyth_solana_receiver" } # Update this line +