diff --git a/hermes/src/aggregate.rs b/hermes/src/aggregate.rs index c1a1def4a..24b59de10 100644 --- a/hermes/src/aggregate.rs +++ b/hermes/src/aggregate.rs @@ -152,10 +152,11 @@ pub enum Update { #[derive(Debug, PartialEq)] pub struct PriceFeedUpdate { - pub price_feed: PriceFeed, - pub slot: Option, - pub received_at: Option, - pub update_data: Option>, + pub price_feed: PriceFeed, + pub slot: Option, + pub received_at: Option, + pub update_data: Option>, + pub prev_publish_time: Option, } #[derive(Debug, PartialEq)] @@ -333,7 +334,7 @@ where .iter() .map(|message_state| match message_state.message { Message::PriceFeedMessage(price_feed) => Ok(PriceFeedUpdate { - price_feed: PriceFeed::new( + price_feed: PriceFeed::new( PriceIdentifier::new(price_feed.feed_id), Price { price: price_feed.price, @@ -348,14 +349,15 @@ where publish_time: price_feed.publish_time, }, ), - received_at: Some(message_state.received_at), - slot: Some(message_state.slot), - update_data: Some( + received_at: Some(message_state.received_at), + slot: Some(message_state.slot), + update_data: Some( construct_update_data(vec![message_state.clone().into()])? .into_iter() .next() .ok_or(anyhow!("Missing update data for message"))?, ), + prev_publish_time: Some(price_feed.prev_publish_time), }), _ => Err(anyhow!("Invalid message state type")), }) @@ -574,7 +576,7 @@ mod test { assert_eq!( price_feeds_with_update_data.price_feeds, vec![PriceFeedUpdate { - price_feed: PriceFeed::new( + price_feed: PriceFeed::new( PriceIdentifier::new(price_feed_message.feed_id), Price { price: price_feed_message.price, @@ -589,11 +591,12 @@ mod test { publish_time: price_feed_message.publish_time, } ), - slot: Some(10), - received_at: price_feeds_with_update_data.price_feeds[0].received_at, // Ignore checking this field. - update_data: price_feeds_with_update_data.price_feeds[0] + slot: Some(10), + received_at: price_feeds_with_update_data.price_feeds[0].received_at, // Ignore checking this field. + update_data: price_feeds_with_update_data.price_feeds[0] .update_data .clone(), // Ignore checking this field. + prev_publish_time: Some(9), }] ); diff --git a/hermes/src/api/types.rs b/hermes/src/api/types.rs index 039ed7f8f..ab2a5e385 100644 --- a/hermes/src/api/types.rs +++ b/hermes/src/api/types.rs @@ -55,6 +55,8 @@ pub struct RpcPriceFeedMetadata { pub emitter_chain: u16, #[schema(value_type = Option, example=doc_examples::timestamp_example)] pub price_service_receive_time: Option, + #[schema(value_type = Option, example=doc_examples::timestamp_example)] + pub prev_publish_time: Option, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] @@ -98,6 +100,7 @@ impl RpcPriceFeed { emitter_chain: Chain::Pythnet.into(), price_service_receive_time: price_feed_update.received_at, slot: price_feed_update.slot, + prev_publish_time: price_feed_update.prev_publish_time, }), vaa: match binary { false => None, diff --git a/hermes/src/state/benchmarks.rs b/hermes/src/state/benchmarks.rs index 0160d4e56..14969e7f1 100644 --- a/hermes/src/state/benchmarks.rs +++ b/hermes/src/state/benchmarks.rs @@ -68,6 +68,7 @@ impl TryFrom for PriceFeedsWithUpdateData { slot: None, received_at: None, update_data: None, + prev_publish_time: None, // TODO: Set this field when Benchmarks API supports it. }) .collect::>(), update_data: benchmark_updates.binary.try_into()?, diff --git a/package-lock.json b/package-lock.json index ab247a76b..c3ba28dfd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57440,7 +57440,7 @@ }, "price_service/client/js": { "name": "@pythnetwork/price-service-client", - "version": "1.7.0", + "version": "1.8.0", "license": "Apache-2.0", "dependencies": { "@pythnetwork/price-service-sdk": "*", @@ -57530,7 +57530,7 @@ }, "price_service/sdk/js": { "name": "@pythnetwork/price-service-sdk", - "version": "1.3.0", + "version": "1.4.0", "license": "Apache-2.0", "devDependencies": { "@types/jest": "^29.4.0", @@ -57966,7 +57966,7 @@ }, "target_chains/aptos/sdk/js": { "name": "@pythnetwork/pyth-aptos-js", - "version": "1.3.0", + "version": "1.4.0", "license": "Apache-2.0", "dependencies": { "@pythnetwork/price-service-client": "*", @@ -58135,7 +58135,7 @@ }, "target_chains/cosmwasm/sdk/js": { "name": "@pythnetwork/pyth-terra-js", - "version": "1.4.0", + "version": "1.5.0", "license": "Apache-2.0", "dependencies": { "@pythnetwork/price-service-client": "*", @@ -59549,7 +59549,7 @@ }, "target_chains/ethereum/sdk/js": { "name": "@pythnetwork/pyth-evm-js", - "version": "1.28.0", + "version": "1.29.0", "license": "Apache-2.0", "dependencies": { "@pythnetwork/price-service-client": "*", @@ -59680,7 +59680,7 @@ }, "target_chains/sui/sdk/js": { "name": "@pythnetwork/pyth-sui-js", - "version": "1.1.0", + "version": "1.2.0", "license": "Apache-2.0", "dependencies": { "@mysten/sui.js": "^0.37.1", diff --git a/price_service/client/js/package.json b/price_service/client/js/package.json index 10d7f4ddd..261a341ac 100644 --- a/price_service/client/js/package.json +++ b/price_service/client/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/price-service-client", - "version": "1.7.0", + "version": "1.8.0", "description": "Pyth price service client", "author": { "name": "Pyth Data Association" diff --git a/price_service/sdk/js/package.json b/price_service/sdk/js/package.json index 3fb5396ba..dca5b4040 100644 --- a/price_service/sdk/js/package.json +++ b/price_service/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/price-service-sdk", - "version": "1.3.0", + "version": "1.4.0", "description": "Pyth price service SDK", "homepage": "https://pyth.network", "main": "lib/index.js", diff --git a/price_service/sdk/js/src/index.ts b/price_service/sdk/js/src/index.ts index 7b23291a3..3c6ae073e 100644 --- a/price_service/sdk/js/src/index.ts +++ b/price_service/sdk/js/src/index.ts @@ -100,6 +100,10 @@ export class PriceFeedMetadata { * Pythnet slot number of the price */ slot?: number; + /** + * The time that the previous price was published + */ + prevPublishTime?: number; constructor(metadata: { attestationTime?: number; @@ -107,12 +111,14 @@ export class PriceFeedMetadata { receiveTime?: number; sequenceNumber?: number; slot?: number; + prevPublishTime?: number; }) { this.attestationTime = metadata.attestationTime; this.emitterChain = metadata.emitterChain; this.priceServiceReceiveTime = metadata.receiveTime; this.sequenceNumber = metadata.sequenceNumber; this.slot = metadata.slot; + this.prevPublishTime = metadata.prevPublishTime; } static fromJson(json: any): PriceFeedMetadata | undefined { @@ -126,6 +132,7 @@ export class PriceFeedMetadata { receiveTime: jsonFeed.price_service_receive_time, sequenceNumber: jsonFeed.sequence_number, slot: jsonFeed.slot, + prevPublishTime: jsonFeed.prev_publish_time, }); } @@ -136,6 +143,7 @@ export class PriceFeedMetadata { price_service_receive_time: this.priceServiceReceiveTime, sequence_number: this.sequenceNumber, slot: this.slot, + prev_publish_time: this.prevPublishTime, }; // this is done to avoid sending undefined values to the server return Convert.priceFeedMetadataToJson(jsonFeed); diff --git a/price_service/sdk/js/src/schemas/PriceFeed.ts b/price_service/sdk/js/src/schemas/PriceFeed.ts index 52e1f500e..f7d59856f 100644 --- a/price_service/sdk/js/src/schemas/PriceFeed.ts +++ b/price_service/sdk/js/src/schemas/PriceFeed.ts @@ -73,6 +73,10 @@ export interface PriceFeedMetadata { * Chain of the emitter */ emitter_chain: number; + /** + * The time that the previous price was published + */ + prev_publish_time?: number; /** * The time that the price service received the price */ @@ -294,6 +298,11 @@ const typeMap: any = { typ: u(undefined, 0), }, { json: "emitter_chain", js: "emitter_chain", typ: 0 }, + { + json: "prev_publish_time", + js: "prev_publish_time", + typ: u(undefined, 0), + }, { json: "price_service_receive_time", js: "price_service_receive_time", diff --git a/price_service/sdk/js/src/schemas/price_feed.json b/price_service/sdk/js/src/schemas/price_feed.json index a3ca6498c..08d3aa894 100644 --- a/price_service/sdk/js/src/schemas/price_feed.json +++ b/price_service/sdk/js/src/schemas/price_feed.json @@ -84,6 +84,11 @@ "description": "Pythnet slot number of the price", "type": "integer", "format": "int64" + }, + "prev_publish_time": { + "description": "The time that the previous price was published", + "type": "integer", + "format": "int64" } } } diff --git a/target_chains/aptos/sdk/js/package.json b/target_chains/aptos/sdk/js/package.json index 797fbd2de..80c94b8a8 100644 --- a/target_chains/aptos/sdk/js/package.json +++ b/target_chains/aptos/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-aptos-js", - "version": "1.3.0", + "version": "1.4.0", "description": "Pyth Network Aptos Utilities", "homepage": "https://pyth.network", "author": { diff --git a/target_chains/cosmwasm/sdk/js/package.json b/target_chains/cosmwasm/sdk/js/package.json index a5d3d65a0..d75afd7b9 100644 --- a/target_chains/cosmwasm/sdk/js/package.json +++ b/target_chains/cosmwasm/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-terra-js", - "version": "1.4.0", + "version": "1.5.0", "description": "Pyth Network Terra Utils in JS", "homepage": "https://pyth.network", "author": { diff --git a/target_chains/ethereum/sdk/js/package.json b/target_chains/ethereum/sdk/js/package.json index 5028e7828..64527ce62 100644 --- a/target_chains/ethereum/sdk/js/package.json +++ b/target_chains/ethereum/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-evm-js", - "version": "1.28.0", + "version": "1.29.0", "description": "Pyth Network EVM Utils in JS", "homepage": "https://pyth.network", "author": { diff --git a/target_chains/sui/sdk/js/package.json b/target_chains/sui/sdk/js/package.json index 2aba6be99..40be40f8a 100644 --- a/target_chains/sui/sdk/js/package.json +++ b/target_chains/sui/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-sui-js", - "version": "1.1.0", + "version": "1.2.0", "description": "Pyth Network Sui Utilities", "homepage": "https://pyth.network", "author": { diff --git a/target_chains/sui/sdk/js/src/examples/SuiRelay.ts b/target_chains/sui/sdk/js/src/examples/SuiRelay.ts index f53b6b522..0d15b698f 100644 --- a/target_chains/sui/sdk/js/src/examples/SuiRelay.ts +++ b/target_chains/sui/sdk/js/src/examples/SuiRelay.ts @@ -18,9 +18,8 @@ const argvPromise = yargs(hideBin(process.argv)) type: "array", demandOption: true, }) - .option("price-service", { - description: - "Endpoint URL for the price service. e.g: https://xc-mainnet.pyth.network", + .option("hermes", { + description: "Endpoint URL for Hermes. e.g: https://hermes.pyth.network", type: "string", demandOption: true, }) @@ -52,7 +51,7 @@ async function run() { const argv = await argvPromise; // Fetch the latest price feed update data from the Price Service - const connection = new SuiPriceServiceConnection(argv["price-service"]); + const connection = new SuiPriceServiceConnection(argv["hermes"]); const feeds = argv["feed-id"] as string[]; const priceFeedUpdateData = await connection.getPriceFeedsUpdateData(feeds);