Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/hermes/server/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/hermes/server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hermes"
version = "0.8.0"
version = "0.8.1"
description = "Hermes is an agent that provides Verified Prices from the Pythnet Pyth Oracle."
edition = "2021"

Expand Down
35 changes: 13 additions & 22 deletions apps/hermes/server/src/state/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,6 @@ where
}

let mut twaps = Vec::new();
let mut update_data = Vec::new();

// Iterate through start and end messages together
for (start_message, end_message) in start_messages.iter().zip(end_messages.iter()) {
Expand All @@ -676,34 +675,26 @@ where
end_timestamp: end_twap.publish_time,
down_slots_ratio,
});

// Combine messages for update data
let mut messages = Vec::new();
messages.push(start_message.clone().into());
messages.push(end_message.clone().into());

if let Ok(update) = construct_update_data(messages) {
update_data.push(update);
} else {
tracing::warn!(
"Failed to construct update data for price feed {:?}",
start_twap.feed_id
);
continue;
}
}
Err(e) => {
tracing::warn!(
return Err(anyhow!(
"Failed to calculate TWAP for price feed {:?}: {}",
start_twap.feed_id,
e
);
continue;
));
}
}
}
}

// Construct update data.
// update_data[0] will contain the start VAA and merkle proofs
// update_data[1] will contain the end VAA and merkle proofs
let start_updates =
construct_update_data(start_messages.into_iter().map(Into::into).collect())?;
let end_updates = construct_update_data(end_messages.into_iter().map(Into::into).collect())?;
let update_data = vec![start_updates, end_updates];

Ok(TwapsWithUpdateData { twaps, update_data })
}

Expand Down Expand Up @@ -1316,10 +1307,10 @@ mod test {
assert_eq!(twap_2.start_timestamp, 100);
assert_eq!(twap_2.end_timestamp, 200);

// Verify update data contains both start and end messages for both feeds
// Each update_data element contains a VAA and merkle proofs for both feeds
assert_eq!(result.update_data.len(), 2);
assert_eq!(result.update_data[0].len(), 2); // Should contain 2 messages
assert_eq!(result.update_data[1].len(), 2); // Should contain 2 messages
assert_eq!(result.update_data[0].len(), 1); // Start update
assert_eq!(result.update_data[1].len(), 1); // End update
}
#[tokio::test]

Expand Down
2 changes: 1 addition & 1 deletion price_service/sdk/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/price-service-sdk",
"version": "1.7.1",
"version": "1.8.0",
"description": "Pyth price service SDK",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand Down
49 changes: 48 additions & 1 deletion price_service/sdk/js/src/AccumulatorUpdateData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ const MAJOR_VERSION = 1;
const MINOR_VERSION = 0;
const KECCAK160_HASH_SIZE = 20;
const PRICE_FEED_MESSAGE_VARIANT = 0;
const TWAP_MESSAGE_VARIANT = 1;

export type AccumulatorUpdateData = {
vaa: Buffer;
updates: { message: Buffer; proof: number[][] }[];
};

export type PriceFeedMessage = {
feedId: Buffer;
price: BN;
Expand All @@ -22,13 +22,25 @@ export type PriceFeedMessage = {
emaConf: BN;
};

export type TwapMessage = {
feedId: Buffer;
cumulativePrice: BN;
cumulativeConf: BN;
numDownSlots: BN;
exponent: number;
publishTime: BN;
prevPublishTime: BN;
publishSlot: BN;
};

export function isAccumulatorUpdateData(updateBytes: Buffer): boolean {
return (
updateBytes.toString("hex").slice(0, 8) === ACCUMULATOR_MAGIC &&
updateBytes[4] === MAJOR_VERSION &&
updateBytes[5] === MINOR_VERSION
);
}

export function parsePriceFeedMessage(message: Buffer): PriceFeedMessage {
let cursor = 0;
const variant = message.readUInt8(cursor);
Expand Down Expand Up @@ -64,6 +76,41 @@ export function parsePriceFeedMessage(message: Buffer): PriceFeedMessage {
};
}

export function parseTwapMessage(message: Buffer): TwapMessage {
let cursor = 0;
const variant = message.readUInt8(cursor);
if (variant !== TWAP_MESSAGE_VARIANT) {
throw new Error("Not a twap message");
}
cursor += 1;
const feedId = message.subarray(cursor, cursor + 32);
cursor += 32;
const cumulativePrice = new BN(message.subarray(cursor, cursor + 16), "be");
cursor += 16;
const cumulativeConf = new BN(message.subarray(cursor, cursor + 16), "be");
cursor += 16;
const numDownSlots = new BN(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const exponent = message.readInt32BE(cursor);
cursor += 4;
const publishTime = new BN(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const prevPublishTime = new BN(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const publishSlot = new BN(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
return {
feedId,
cumulativePrice,
cumulativeConf,
numDownSlots,
exponent,
publishTime,
prevPublishTime,
publishSlot,
};
}

/**
* An AccumulatorUpdateData contains a VAA and a list of updates. This function returns a new serialized AccumulatorUpdateData with only the updates in the range [start, end).
*/
Expand Down
1 change: 1 addition & 0 deletions price_service/sdk/js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export {
parseAccumulatorUpdateData,
AccumulatorUpdateData,
parsePriceFeedMessage,
parseTwapMessage,
} from "./AccumulatorUpdateData";

/**
Expand Down
Loading