Skip to content
This repository was archived by the owner on Mar 14, 2024. It is now read-only.

Commit

Permalink
Merge pull request #6 from pyth-network/price-feed-metadata
Browse files Browse the repository at this point in the history
add metadata to price feed
  • Loading branch information
cctdaniel authored Sep 6, 2022
2 parents 7fd8ae7 + 5388085 commit 8bdd411
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 15 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/pyth-sdk-js",
"version": "0.2.0",
"version": "0.3.0",
"description": "Pyth Network SDK in JS",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand All @@ -13,7 +13,7 @@
"test": "jest",
"build": "tsc",
"format": "prettier --write \"src/**/*.ts\"",
"gen-ts-schema": "quicktype --src-lang schema src/schemas/price_feed.json -o src/schemas/PriceFeed.ts --raw-type any && prettier --write \"src/schemas/*.ts\"",
"gen-ts-schema": "quicktype --src-lang schema src/schemas/price_feed.json -o src/schemas/PriceFeed.ts --raw-type any --converters all-objects && prettier --write \"src/schemas/*.ts\"",
"lint": "eslint src/",
"prepare": "npm run build",
"prepublishOnly": "npm test && npm run lint",
Expand Down
39 changes: 36 additions & 3 deletions src/__tests__/PriceFeed.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Price, PriceFeed, PriceStatus } from "../index";
import { Price, PriceFeed, PriceFeedMetadata, PriceStatus } from "../index";

beforeAll(() => {
jest.useFakeTimers();
Expand Down Expand Up @@ -42,8 +42,7 @@ test("Parsing Price Feed works as expected", () => {
new Price("1", 4, "10")
);
expect(priceFeed.getLatestAvailablePriceWithinDuration(5)).toBeUndefined();

expect(priceFeed.toJson()).toStrictEqual(data);
expect(priceFeed.toJson()).toEqual(data);
});

test("getCurrentPrice returns undefined if status is not Trading", () => {
Expand Down Expand Up @@ -99,3 +98,37 @@ test("getLatestAvailablePrice returns prevPrice when status is not Trading", ()
);
expect(priceFeed.getLatestAvailablePriceWithinDuration(10)).toBeUndefined();
});

test("getMetadata returns PriceFeedMetadata as expected", () => {
const data = {
conf: "1",
ema_conf: "2",
ema_price: "3",
expo: 4,
id: "abcdef0123456789",
max_num_publishers: 6,
metadata: {
attestation_time: 7,
emitter_chain: 8,
sequence_number: 9,
},
num_publishers: 10,
prev_conf: "11",
prev_price: "12",
prev_publish_time: 13,
price: "14",
product_id: "0123456789abcdef",
publish_time: 16,
status: PriceStatus.Unknown,
};

const priceFeed = PriceFeed.fromJson(data);

expect(priceFeed.getMetadata()).toStrictEqual(
PriceFeedMetadata.fromJson({
attestation_time: 7,
emitter_chain: 8,
sequence_number: 9,
})
);
});
84 changes: 80 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Convert, PriceFeed as JsonPriceFeed } from "./schemas/PriceFeed";
import {
Convert,
PriceFeed as JsonPriceFeed,
PriceFeedMetadata as JsonPriceFeedMetadata,
} from "./schemas/PriceFeed";

export type UnixTimestamp = number;
export type DurationInSeconds = number;
Expand Down Expand Up @@ -53,6 +57,58 @@ export enum PriceStatus {
Unknown = "Unknown",
}

/**
* Metadata about the price
*
* Represents metadata of a price feed.
*/
export class PriceFeedMetadata {
/**
* Attestation time of the price
*/
attestationTime: number;
/**
* Chain of the emitter
*/
emitterChain: number;
/**
* Sequence number of the price
*/
sequenceNumber: number;

constructor(metadata: {
attestationTime: number;
emitterChain: number;
sequenceNumber: number;
}) {
this.attestationTime = metadata.attestationTime;
this.emitterChain = metadata.emitterChain;
this.sequenceNumber = metadata.sequenceNumber;
}

static fromJson(json: any): PriceFeedMetadata | undefined {
if (json === undefined) {
return undefined;
}
const jsonFeed: JsonPriceFeedMetadata = Convert.toPriceFeedMetadata(json);
return new PriceFeedMetadata({
attestationTime: jsonFeed.attestation_time,
emitterChain: jsonFeed.emitter_chain,
sequenceNumber: jsonFeed.sequence_number,
});
}

toJson(): any {
const jsonFeed: JsonPriceFeedMetadata = {
attestation_time: this.attestationTime,
emitter_chain: this.emitterChain,
sequence_number: this.sequenceNumber,
};
// this is done to avoid sending undefined values to the server
return Convert.priceFeedMetadataToJson(jsonFeed);
}
}

/**
* Pyth Price Feed
*
Expand Down Expand Up @@ -84,6 +140,10 @@ export class PriceFeed {
* Maximum number of allowed publishers that can contribute to a price.
*/
maxNumPublishers: number;
/**
* Metadata about the price
*/
metadata?: PriceFeedMetadata;
/**
* Number of publishers that made up current aggregate.
*/
Expand Down Expand Up @@ -124,6 +184,7 @@ export class PriceFeed {
expo: number;
id: HexString;
maxNumPublishers: number;
metadata?: PriceFeedMetadata;
numPublishers: number;
prevConf: string;
prevPrice: string;
Expand All @@ -139,6 +200,7 @@ export class PriceFeed {
this.expo = rawValues.expo;
this.id = rawValues.id;
this.maxNumPublishers = rawValues.maxNumPublishers;
this.metadata = rawValues.metadata;
this.numPublishers = rawValues.numPublishers;
this.prevConf = rawValues.prevConf;
this.prevPrice = rawValues.prevPrice;
Expand All @@ -158,6 +220,7 @@ export class PriceFeed {
expo: jsonFeed.expo,
id: jsonFeed.id,
maxNumPublishers: jsonFeed.max_num_publishers,
metadata: PriceFeedMetadata.fromJson(jsonFeed.metadata),
numPublishers: jsonFeed.num_publishers,
prevConf: jsonFeed.prev_conf,
prevPrice: jsonFeed.prev_price,
Expand All @@ -177,6 +240,7 @@ export class PriceFeed {
expo: this.expo,
id: this.id,
max_num_publishers: this.maxNumPublishers,
metadata: this.metadata?.toJson(),
num_publishers: this.numPublishers,
prev_conf: this.prevConf,
prev_price: this.prevPrice,
Expand Down Expand Up @@ -259,18 +323,30 @@ export class PriceFeed {
* @returns a struct containing the latest available price, confidence interval and the exponent for
* both numbers, or `undefined` if no price update occurred within `duration` seconds of the current time.
*/
getLatestAvailablePriceWithinDuration(duration: DurationInSeconds): Price | undefined {
getLatestAvailablePriceWithinDuration(
duration: DurationInSeconds
): Price | undefined {
const [price, timestamp] = this.getLatestAvailablePriceUnchecked();

const currentTime: UnixTimestamp = Math.floor(Date.now() / 1000);

// This checks the absolute difference as a sanity check
// for the cases that the system time is behind or price
// feed timestamp happen to be in the future (a bug).
// feed timestamp happen to be in the future (a bug).
if (Math.abs(currentTime - timestamp) > duration) {
return undefined;
}

return price;
}

/**
* Get the price feed metadata.
*
* @returns a struct containing the attestation time, emitter chain, and the sequence number.
* Returns `undefined` if metadata is currently unavailable.
*/
getMetadata(): PriceFeedMetadata | undefined {
return this.metadata;
}
}
45 changes: 45 additions & 0 deletions src/schemas/PriceFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export interface PriceFeed {
* Maximum number of allowed publishers that can contribute to a price.
*/
max_num_publishers: number;
/**
* Metadata about the price
*/
metadata?: PriceFeedMetadata;
/**
* Number of publishers that made up current aggregate.
*/
Expand Down Expand Up @@ -69,6 +73,26 @@ export interface PriceFeed {
status: PriceStatus;
}

/**
* Metadata about the price
*
* Represents metadata of a price feed.
*/
export interface PriceFeedMetadata {
/**
* Attestation time of the price
*/
attestation_time: number;
/**
* Chain of the emitter
*/
emitter_chain: number;
/**
* Sequence number of the price
*/
sequence_number: number;
}

/**
* Status of price (Trading is valid).
*
Expand All @@ -91,6 +115,14 @@ export class Convert {
public static priceFeedToJson(value: PriceFeed): any {
return uncast(value, r("PriceFeed"));
}

public static toPriceFeedMetadata(json: any): PriceFeedMetadata {
return cast(json, r("PriceFeedMetadata"));
}

public static priceFeedMetadataToJson(value: PriceFeedMetadata): any {
return uncast(value, r("PriceFeedMetadata"));
}
}

function invalidValue(typ: any, val: any, key: any = ""): never {
Expand Down Expand Up @@ -249,6 +281,11 @@ const typeMap: any = {
{ json: "expo", js: "expo", typ: 0 },
{ json: "id", js: "id", typ: "" },
{ json: "max_num_publishers", js: "max_num_publishers", typ: 0 },
{
json: "metadata",
js: "metadata",
typ: u(undefined, r("PriceFeedMetadata")),
},
{ json: "num_publishers", js: "num_publishers", typ: 0 },
{ json: "prev_conf", js: "prev_conf", typ: "" },
{ json: "prev_price", js: "prev_price", typ: "" },
Expand All @@ -260,5 +297,13 @@ const typeMap: any = {
],
"any"
),
PriceFeedMetadata: o(
[
{ json: "attestation_time", js: "attestation_time", typ: 0 },
{ json: "emitter_chain", js: "emitter_chain", typ: 0 },
{ json: "sequence_number", js: "sequence_number", typ: 0 },
],
"any"
),
PriceStatus: ["Auction", "Halted", "Trading", "Unknown"],
};
37 changes: 31 additions & 6 deletions src/schemas/price_feed.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@
"$ref": "#/definitions/PriceStatus"
}
]
},
"metadata": {
"description": "Metadata about the price",
"allOf": [
{
"$ref": "#/definitions/PriceFeedMetadata"
}
]
}
},
"definitions": {
Expand All @@ -103,12 +111,29 @@
"PriceStatus": {
"description": "Represents availability status of a price feed.",
"type": "string",
"enum": [
"Unknown",
"Trading",
"Halted",
"Auction"
]
"enum": ["Unknown", "Trading", "Halted", "Auction"]
},
"PriceFeedMetadata": {
"description": "Represents metadata of a price feed.",
"type": "object",
"required": ["attestation_time", "emitter_chain", "sequence_number"],
"properties": {
"attestation_time": {
"description": "Attestation time of the price",
"type": "integer",
"format": "int64"
},
"emitter_chain": {
"description": "Chain of the emitter",
"type": "integer",
"format": "int16"
},
"sequence_number": {
"description": "Sequence number of the price",
"type": "integer",
"format": "int64"
}
}
}
}
}

0 comments on commit 8bdd411

Please sign in to comment.