@typus/typus-sdk 1.9.4 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,15 @@
1
1
  export declare function getPairPrices(pair: string, startTs: string, endTs: string): Promise<any>;
2
2
  export declare function getLatestPrice(pair: string): Promise<string>;
3
- export declare function getPythLatestPrice(): Promise<Map<string, number> | undefined>;
3
+ /**
4
+ * Fetch latest display prices for every mapped token.
5
+ * @param accessToken Optional Lazer JWT / API key; falls back to PYTH_LAZER_TOKEN env.
6
+ */
7
+ export declare function getPythLatestPrice(accessToken?: string): Promise<Map<string, number>>;
4
8
  /**
5
9
  * Fetch latest Pyth prices for the specified symbols.
6
10
  * @param symbols Array of token symbols (e.g., ["BTC", "ETH"]) to fetch prices for.
11
+ * @param accessToken Optional Lazer JWT / API key; falls back to PYTH_LAZER_TOKEN env.
7
12
  * @returns Map where keys are token symbols and values are their latest prices.
8
13
  */
9
- export declare function getPythLatestPriceBySymbols(symbols: string[]): Promise<Map<string, number>>;
14
+ export declare function getPythLatestPriceBySymbols(symbols: string[], accessToken?: string): Promise<Map<string, number>>;
10
15
  export declare function getLatestPriceUSD(): Promise<Map<string, number>>;
@@ -51,6 +51,15 @@ var __read = (this && this.__read) || function (o, n) {
51
51
  }
52
52
  return ar;
53
53
  };
54
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
55
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
56
+ if (ar || !(i in from)) {
57
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
58
+ ar[i] = from[i];
59
+ }
60
+ }
61
+ return to.concat(ar || Array.prototype.slice.call(from));
62
+ };
54
63
  Object.defineProperty(exports, "__esModule", { value: true });
55
64
  exports.getPairPrices = getPairPrices;
56
65
  exports.getLatestPrice = getLatestPrice;
@@ -113,85 +122,112 @@ function getLatestPrice(pair) {
113
122
  });
114
123
  });
115
124
  }
116
- function getPythLatestPrice() {
125
+ // Pyth Lazer (Pro) numeric feed ids for the display-price helpers below.
126
+ // hermes.pyth.network requires an API key from 2026-08-18 and no key form is
127
+ // browser-safe there, so these helpers fetch from the Lazer `/price` endpoint
128
+ // instead — it accepts the short-lived JWTs a browser can hold.
129
+ // - XAU is priced off XAUT/USD (feed 172): the metal-spot feed 346 is not
130
+ // entitled on our key, and one unentitled id 403s the whole batch.
131
+ // - USOIL / XAG / USDJPY are unentitled with no crypto proxy — dropped.
132
+ // - Several Sui-ecosystem feeds are inactive upstream as of 2026-07-20
133
+ // (TURBOS, SCA, AFSUI, NAVX, BUCK, VSUI, HASUI) and return no row until
134
+ // Pyth reactivates them.
135
+ var lazerDisplayIds = {
136
+ SUI: 11,
137
+ CETUS: 401,
138
+ USDC: 7,
139
+ BTC: 1,
140
+ ETH: 2,
141
+ SOL: 6,
142
+ TURBOS: 599,
143
+ APT: 28,
144
+ USDT: 8,
145
+ DOGE: 13,
146
+ INJ: 46,
147
+ SEI: 51,
148
+ JUP: 92,
149
+ SCA: 545,
150
+ AFSUI: 353,
151
+ NAVX: 509,
152
+ USDY: 276,
153
+ BUCK: 390,
154
+ VSUI: 622,
155
+ HASUI: 443,
156
+ AUSD: 367,
157
+ DEEP: 173,
158
+ BLUE: 381,
159
+ XAU: 172,
160
+ WAL: 624,
161
+ HYPE: 110,
162
+ XRP: 14,
163
+ HAEDAL: 648,
164
+ };
165
+ var LAZER_PRICE_URL = "https://pyth.dourolabs.app/v1/fixed_rate@1000ms/price";
166
+ function fetchLazerDisplayPrices(names, accessToken) {
117
167
  return __awaiter(this, void 0, void 0, function () {
118
- var keys, apiUrlWithParams, response, map, data;
168
+ var entries, ids, timestamp, query, token, map, response, rows, priceById;
119
169
  return __generator(this, function (_a) {
120
170
  switch (_a.label) {
121
171
  case 0:
122
- keys = Object.keys(pythId)
123
- .map(function (key) { return "ids[]=".concat(key); })
124
- .join("&");
125
- apiUrlWithParams = "https://hermes.pyth.network/api/latest_price_feeds?".concat(keys);
126
- return [4 /*yield*/, fetch(apiUrlWithParams, {
172
+ entries = names.map(function (name) { return [name, lazerDisplayIds[name]]; }).filter(function (_a) {
173
+ var _b = __read(_a, 2), id = _b[1];
174
+ return id != null;
175
+ });
176
+ ids = __spreadArray([], __read(new Set(entries.map(function (_a) {
177
+ var _b = __read(_a, 2), id = _b[1];
178
+ return id;
179
+ }))), false);
180
+ timestamp = Math.floor((Date.now() - 2000) / 1000) * 1000000;
181
+ query = ids.map(function (id) { return "ids=".concat(id); }).join("&");
182
+ token = accessToken !== null && accessToken !== void 0 ? accessToken : process.env.PYTH_LAZER_TOKEN;
183
+ map = new Map();
184
+ return [4 /*yield*/, fetch("".concat(LAZER_PRICE_URL, "?").concat(query, "&timestamp=").concat(timestamp), {
127
185
  method: "GET",
128
- headers: { "Content-Type": "application/json" },
186
+ headers: token ? { Authorization: "Bearer ".concat(token) } : {},
129
187
  })];
130
188
  case 1:
131
189
  response = _a.sent();
132
- map = new Map();
133
- if (!response.ok) return [3 /*break*/, 3];
190
+ if (!response.ok) {
191
+ console.error("Failed to fetch Pyth prices: ".concat(response.status));
192
+ return [2 /*return*/, map];
193
+ }
134
194
  return [4 /*yield*/, response.json()];
135
195
  case 2:
136
- data = _a.sent();
137
- data.forEach(function (p) {
138
- var token = pythId[p.id];
139
- var price = p.price.price / Math.pow(10, -p.price.expo);
140
- map.set(token, price);
196
+ rows = _a.sent();
197
+ priceById = new Map(rows.map(function (r) { return [r.price_feed_id, r.price * Math.pow(10, r.exponent)]; }));
198
+ entries.forEach(function (_a) {
199
+ var _b = __read(_a, 2), name = _b[0], id = _b[1];
200
+ var price = priceById.get(id);
201
+ if (price != null) {
202
+ map.set(name, price);
203
+ }
141
204
  });
142
205
  return [2 /*return*/, map];
143
- case 3: return [2 /*return*/];
144
206
  }
145
207
  });
146
208
  });
147
209
  }
210
+ /**
211
+ * Fetch latest display prices for every mapped token.
212
+ * @param accessToken Optional Lazer JWT / API key; falls back to PYTH_LAZER_TOKEN env.
213
+ */
214
+ function getPythLatestPrice(accessToken) {
215
+ return __awaiter(this, void 0, void 0, function () {
216
+ return __generator(this, function (_a) {
217
+ return [2 /*return*/, fetchLazerDisplayPrices(Object.keys(lazerDisplayIds), accessToken)];
218
+ });
219
+ });
220
+ }
148
221
  /**
149
222
  * Fetch latest Pyth prices for the specified symbols.
150
223
  * @param symbols Array of token symbols (e.g., ["BTC", "ETH"]) to fetch prices for.
224
+ * @param accessToken Optional Lazer JWT / API key; falls back to PYTH_LAZER_TOKEN env.
151
225
  * @returns Map where keys are token symbols and values are their latest prices.
152
226
  */
153
- function getPythLatestPriceBySymbols(symbols) {
227
+ function getPythLatestPriceBySymbols(symbols, accessToken) {
154
228
  return __awaiter(this, void 0, void 0, function () {
155
- var idsParam, apiUrlWithParams, response, map, data;
156
229
  return __generator(this, function (_a) {
157
- switch (_a.label) {
158
- case 0:
159
- idsParam = Object.entries(pythId)
160
- .filter(function (_a) {
161
- var _b = __read(_a, 2), id = _b[0], token = _b[1];
162
- return symbols.includes(token);
163
- })
164
- .map(function (_a) {
165
- var _b = __read(_a, 1), id = _b[0];
166
- return "ids[]=".concat(id);
167
- })
168
- .join("&");
169
- apiUrlWithParams = "https://hermes.pyth.network/api/latest_price_feeds?".concat(idsParam);
170
- return [4 /*yield*/, fetch(apiUrlWithParams, {
171
- method: "GET",
172
- headers: { "Content-Type": "application/json" },
173
- })];
174
- case 1:
175
- response = _a.sent();
176
- map = new Map();
177
- if (!response.ok) return [3 /*break*/, 3];
178
- return [4 /*yield*/, response.json()];
179
- case 2:
180
- data = _a.sent();
181
- data.forEach(function (p) {
182
- var token = pythId[p.id];
183
- // Convert price using exponent provided
184
- var price = p.price.price / Math.pow(10, -p.price.expo);
185
- if (symbols.includes(token)) {
186
- map.set(token, price);
187
- }
188
- });
189
- return [3 /*break*/, 4];
190
- case 3:
191
- console.error("Failed to fetch Pyth prices: ".concat(response.status));
192
- _a.label = 4;
193
- case 4: return [2 /*return*/, map];
194
- }
230
+ return [2 /*return*/, fetchLazerDisplayPrices(symbols, accessToken)];
195
231
  });
196
232
  });
197
233
  }
@@ -1,29 +1,8 @@
1
1
  import { TOKEN } from "../../../src/constants";
2
- export declare const priceIDs: {
3
- MAINNET: {
4
- [key in TOKEN]?: string;
5
- };
6
- TESTNET: {
7
- [key in TOKEN]?: string;
8
- };
2
+ export declare const feedIds: {
3
+ [key in TOKEN]: number;
9
4
  };
10
- export declare const priceInfoObjectIds: {
11
- MAINNET: {
12
- [key in TOKEN]?: string;
13
- };
14
- TESTNET: {
15
- [key in TOKEN]?: string;
16
- };
17
- };
18
- export declare const wormholeStateId: {
19
- MAINNET: string;
20
- TESTNET: string;
21
- };
22
- export declare const pythStateId: {
23
- MAINNET: string;
24
- TESTNET: string;
25
- };
26
- export declare const endpoint: {
5
+ export declare const lazerStateId: {
27
6
  MAINNET: string;
28
7
  TESTNET: string;
29
8
  };
@@ -1,195 +1,81 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.endpoint = exports.pythStateId = exports.wormholeStateId = exports.priceInfoObjectIds = exports.priceIDs = void 0;
4
- // You can find the IDs of prices at https://pyth.network/developers/price-feed-ids
5
- exports.priceIDs = {
6
- MAINNET: {
7
- // Pyth EVM Stable
8
- SUI: "0x23d7315113f5b1d3ba7a83604c44b94d79f4fd69af77f804fc7f920a6dc65744",
9
- CETUS: "0xe5b274b2611143df055d6e7cd8d93fe1961716bcd4dca1cad87a83bc1e78c1ef",
10
- USDC: "0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a",
11
- WBTC: "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
12
- wETH: "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace",
13
- sbETH: "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace",
14
- wSOL: "0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d",
15
- TURBOS: "0xf9c2e890443dd995d0baafc08eea3358be1ffb874f93f99c30b3816c460bbac3",
16
- wAPT: "0x03ae4db29ed4ae33d323568895aa00337e658e348b37509f5372ae51f0af00d5",
17
- wUSDT: "0x2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b",
18
- DOGE: "0xdcef50dd0a4cd2dcc17e45df1676dcb336a11a61c69df7a0299b0150c672d25c",
19
- INJ: "0x7a5bc1d2b56ad029048cd63964b3ad2776eadf812edc1a43a31406cb54bff592",
20
- SEI: "0x53614f1cb0c031d4af66c04cb9c756234adad0e1cee85303795091499a4084eb",
21
- JUP: "0x0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996",
22
- SCA: "0x7e17f0ac105abe9214deb9944c30264f5986bf292869c6bd8e8da3ccd92d79bc",
23
- AFSUI: "0x17cd845b16e874485b2684f8b8d1517d744105dbb904eec30222717f4bc9ee0d",
24
- NAVX: "0x88250f854c019ef4f88a5c073d52a18bb1c6ac437033f5932cd017d24917ab46",
25
- USDY: "0xe393449f6aff8a4b6d3e1165a7c9ebec103685f3b41e60db4277b5b6d10e7326",
26
- BUCK: "0xfdf28a46570252b25fd31cb257973f865afc5ca2f320439e45d95e0394bc7382",
27
- VSUI: "0x57ff7100a282e4af0c91154679c5dae2e5dcacb93fd467ea9cb7e58afdcfde27",
28
- HASUI: "0x6120ffcf96395c70aa77e72dcb900bf9d40dccab228efca59a17b90ce423d5e8",
29
- AUSD: "0xd9912df360b5b7f21a122f15bdd5e27f62ce5e72bd316c291f7c86620e07fb2a",
30
- // These are not available on Pyth
31
- // FUD: "0x6a4090703da959247727f2b490eb21aea95c8684ecfac675f432008830890c75",
32
- DEEP: "0x29bdd5248234e33bd93d3b81100b5fa32eaa5997843847e2c2cb16d7c6d9f7ff",
33
- BLUE: "0x04cfeb7b143eb9c48e9b074125c1a3447b85f59c31164dc20c1beaa6f21f2b6b",
34
- // These are not available on Pyth
35
- // BLUB: "0x5fc11ffe4975b624be495be038da30e30bee2004d8ae6282b5364577ef4ca92c",
36
- HIPPO: "0xf2c5249856da2fbe0221e163b3fed678dd6f76515ab933292dfb4f15a1de8f8c",
37
- STSUI: "0x0449948a9a210481464ea7030734fa79f59b751c2f411cfb1ba56b5f69e4a62a",
38
- NS: "0xbb5ff26e47a3a6cc7ec2fce1db996c2a145300edc5acaabe43bf9ff7c5dd5d32",
39
- WAL: "0xeba0732395fae9dec4bae12e52760b35fc1c5671e2da8b449c9af4efe5d54341",
40
- LBTC: "0x8f257aab6e7698bb92b15511915e593d6f8eae914452f781874754b03d0c612b",
41
- JPY: "0xef2c98c804ba503c6a707e38be4dfbb16683775f195b091252bf24693042fd52",
42
- XAU: "0x765d2ba906dbc32ca17cc11f5310a89e9ee1f6420508c63861f2f8ba4ee34bb2",
43
- XAG: "0xf2fb02c32b055c805e7238d628e5e9dadef274376114eb1f012337cabe93871e",
44
- USOIL: "0x925ca92ff005ae943c158e3563f59698ce7e75c5a8c8dd43303a0a154887b3e6",
45
- HAEDAL: "0xe67d98cc1fbd94f569d5ba6c3c3c759eb3ffc5d2b28e64538a53ae13efad8fd1",
46
- HYPE: "0x4279e31cc369bbcc2faf022b382b080e32a8e689ff20fbc530d2a603eb6cd98b",
47
- XRP: "0xec5d399846a9209f3fe5881d70aae9268c94339ff9817e8d18ff19fa05eea1c8",
48
- xBTC: "0xae8f269ed9c4bed616c99a98cf6dfe562bd3202e7f91821a471ff854713851b4",
49
- TBTC: "0x56a3121958b01f99fdc4e1fd01e81050602c7ace3a571918bb55c6a96657cca9",
50
- BNB: "0x2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c4f",
51
- QQQX: "0x178a6f73a5aede9d0d682e86b0047c9f333ed0efe5c6537ca937565219c4054d",
52
- SPYX: "0x2817b78438c769357182c04346fddaad1178c82f4048828fe0997c3c64624e14",
53
- NVDAX: "0x4244d07890e4610f46bbde67de8f43a4bf8b569eebe904f136b469f148503b7f",
54
- TSLAX: "0x47a156470288850a440df3a6ce85a55917b813a19bb5b31128a33a986566a362",
55
- AAPLX: "0x978e6cc68a119ce066aa830017318563a9ed04ec3a0a6439010fc11296a58675",
56
- GOOGLX: "0xb911b0329028cd0283e4259c33809d62942bd2716a58084e5f31d64c00b5424e",
57
- METAX: "0xbf3e5871be3f80ab7a4d1f1fd039145179fb58569e159aee1ccd472868ea5900",
58
- COINX: "0x641435d5dffb5311140b480517c79986d8488d5cf08a11eec53b83ad02cab33f",
59
- CRCLX: "0xc13184461c0c80d98ffcd89be627c2220b94a96c7c67f0c4b16bc12fd3b17758",
60
- HOODX: "0xdd49a9ac6df5cbfa9d8fc6371f7ae927a74d5c6763c1c01b4220d70314c647f9",
61
- MSTRX: "0x53f95ba4e23ed15ea56083e2ee9a5eec48055d6f59033d4bb95f1ca2a2349c28",
62
- },
63
- TESTNET: {
64
- // Pyth EVM Beta
65
- SUI: "0x50c67b3fd225db8912a424dd4baed60ffdde625ed2feaaf283724f9608fea266",
66
- CETUS: "0xcb324dafd531712dd31c39969ae0246ee4c6ae167257bcf8ac27e28ca35e6a0c",
67
- USDC: "0x41f3625971ca2ed2263e78573fe5ce23e13d2558ed3f2e47ab0f84fb9e7ae722",
68
- wUSDC: "0x41f3625971ca2ed2263e78573fe5ce23e13d2558ed3f2e47ab0f84fb9e7ae722", // USDC/USD price ID
69
- WBTC: "0xf9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b",
70
- wETH: "0xca80ba6dc32e08d06f1aa886011eed1d77c77be9eb761cc10d72b7d0a2fd57a6",
71
- sbETH: "0xca80ba6dc32e08d06f1aa886011eed1d77c77be9eb761cc10d72b7d0a2fd57a6",
72
- wSOL: "0xfe650f0367d4a7ef9815a593ea15d36593f0643aaaf0149bb04be67ab851decd",
73
- TURBOS: "0x3f545e3f4ec9fd8eb3b9d9d6071a1da361f6729fa1b93d1d1baca3379551d99e",
74
- wAPT: "0x44a93dddd8effa54ea51076c4e851b6cbbfd938e82eb90197de38fe8876bb66e",
75
- wUSDT: "0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588",
76
- // DOGE: "0x31775e1d6897129e8a84eeba975778fb50015b88039e9bc140bbd839694ac0ae",
77
- INJ: "0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3",
78
- SEI: "0x95f1aef92c74670d40f1f37ee6fb158ffd6a0f8913b07b9e61087f9b7273b11c",
79
- JUP: "0xe92860f24d56f9ba9894658202633062744556e98fb3e924b4a2694d82f05737",
80
- SCA: "0xeacabc6304d11fc10a757f63286ef44415d8e91b7a1a525ae94a7ec9398b73f3",
81
- AFSUI: "0xd213e2929116af56c3ce71a1acee874f1dd03f42567b552085fa9d8ce8ce7134",
82
- NAVX: "0x946292ad3f481f36f5e558726cf4974e2a7a34598bf15d2abe3619e7b6a8db91",
83
- USDY: "0xc222a1d2b89218c034b515e738b19ee268c105d8ede44d95b279f1c8bfbb68af",
84
- BUCK: "0xed0899e3a021f1e59031ad365bb3014d78f9ba5556e263692d3508b9272daabf",
85
- VSUI: "0xabb2661c87ecac9f93eade3dd089dbb6e9eb4083eba3b35371ee6f8fa1133752",
86
- HASUI: "0xb675212df51f05b159e31e3047895778df9df1c870587102a06fc96100853361",
87
- AUSD: "0xf1882d28af56a63960f0c313e6c76eab8f802f15e801ebfca223412b55375fe3",
88
- FUD: "0x15f63843dcccf30510f48ff6e363f9ead3b0b05d7f7dde6e3890a7e9e4d83e4a",
89
- DEEP: "0xe18bf5fa857d5ca8af1f6a458b26e853ecdc78fc2f3dc17f4821374ad94d8327",
90
- BLUE: "0x64559fcff99ed360543d7f4778f4712d2dc5c303ec1ac98f084c88c647ff7689",
91
- BLUB: "0xc171055a63e9b4c09e29cc018129379e0a8581512f6726f5bfe5429985773312",
92
- HIPPO: "0x082736b80698caf1379f0ad10a637668ccd531a96133d1f5053df97bffd2933b",
93
- STSUI: "0xda703fbee4d7ee09aba630ef809efd79d162202bdf976ae8258875207ebd5557",
94
- NS: "0x65aca56071505735c09091deb8733fdeba265bd9723dd4fb326b5ffd6843b3a3",
95
- WAL: "0xa6ba0195b5364be116059e401fb71484ed3400d4d9bfbdf46bd11eab4f9b7cea",
96
- LBTC: "0x29448db25efe8c72afe3a3c0c0631337408bd3cbc5f09d3dab0754460a965dae",
97
- JPY: "0x20a938f54b68f1f2ef18ea0328f6dd0747f8ea11486d22b021e83a900be89776",
98
- XAU: "0x30a19158f5a54c0adf8fb7560627343f22a1bc852b89d56be1accdc5dbf96d0e",
99
- XAG: "0x321ba4d608fa75ba76d6d73daa715abcbdeb9dba02257f05a1b59178b49f599b",
100
- USOIL: "0x24d84a7ab973231e4394015ece17a2155174123be2f8e38c751e17fbd2fcedad",
101
- TBTC: "0xed1b51d4fb17e8c8b54a0c5bdbd59b38a0304d032287eb38d907374f16b5f535",
102
- BNB: "0xecf553770d9b10965f8fb64771e93f5690a182edc32be4a3236e0caaa6e0581a",
103
- xBTC: "0xfd5464ac394d347958864c8a93dc71f2be56a5943fefc459a0074dc314b415d8",
104
- },
3
+ exports.lazerStateId = exports.feedIds = void 0;
4
+ // Pyth Lazer numeric feed IDs (u32). Source: https://docs.pyth.network/lazer/price-feed-ids
5
+ // Same-asset wrappers (wETH, sbETH, wSOL, wAPT, wUSDT, wUSDC, sbBTC) map to their
6
+ // underlying base/USD feed; LSTs and BTC derivatives (AFSUI, VSUI, HASUI, STSUI,
7
+ // LBTC, xBTC, TBTC, WBTC) use their own dedicated feeds, matching typus-rust.
8
+ // XAU is priced off Crypto.XAUT/USD 172 (24/7; spot 346 is market-hours gated).
9
+ exports.feedIds = {
10
+ // placeholder feed ID for Typus Index; not live on Pyth Lazer
11
+ TYPUS: 0,
12
+ FUD: 0,
13
+ BLUB: 0,
14
+ LIQ: 0,
15
+ MFUD: 0,
16
+ MBLUB: 0,
17
+ MLIQ: 0,
18
+ SPSUI: 0,
19
+ sSCA: 0,
20
+ TEXP: 0,
21
+ USD: 0,
22
+ sbBTC: 1,
23
+ WBTC: 103,
24
+ xBTC: 1598,
25
+ TBTC: 588,
26
+ LBTC: 468,
27
+ wETH: 2,
28
+ sbETH: 2,
29
+ wSOL: 6,
30
+ USDC: 7,
31
+ wUSDC: 7,
32
+ sbUSDT: 8,
33
+ wUSDT: 8,
34
+ SUI: 11,
35
+ AFSUI: 353,
36
+ VSUI: 622,
37
+ HASUI: 443,
38
+ STSUI: 736,
39
+ DOGE: 13,
40
+ XRP: 14,
41
+ BNB: 15,
42
+ wAPT: 28,
43
+ INJ: 46,
44
+ SEI: 51,
45
+ JUP: 92,
46
+ HYPE: 110,
47
+ DEEP: 173,
48
+ USDY: 276,
49
+ JPY: 340,
50
+ USOIL: 657,
51
+ XAG: 345,
52
+ XAU: 172,
53
+ AUSD: 367,
54
+ BLUE: 381,
55
+ BUCK: 390,
56
+ CETUS: 401,
57
+ HIPPO: 448,
58
+ NAVX: 509,
59
+ NS: 514,
60
+ SCA: 545,
61
+ TURBOS: 599,
62
+ WAL: 624,
63
+ HAEDAL: 648,
64
+ AAPLX: 1792,
65
+ COINX: 1796,
66
+ CRCLX: 1798,
67
+ GOOGLX: 1808,
68
+ HOODX: 1815,
69
+ METAX: 1824,
70
+ MSTRX: 1827,
71
+ NVDAX: 1833,
72
+ QQQX: 1837,
73
+ SPYX: 1843,
74
+ TSLAX: 1847,
105
75
  };
106
- exports.priceInfoObjectIds = {
107
- MAINNET: {
108
- SUI: "0x801dbc2f0053d34734814b2d6df491ce7807a725fe9a01ad74a07e9c51396c37",
109
- USDC: "0x5dec622733a204ca27f5a90d8c2fad453cc6665186fd5dff13a83d0b6c9027ab",
110
- wUSDT: "0x985e3db9f93f76ee8bace7c3dd5cc676a096accd5d9e09e9ae0fb6e492b14572",
111
- WBTC: "0x9a62b4863bdeaabdc9500fce769cf7e72d5585eeb28a6d26e4cafadc13f76ab2",
112
- wETH: "0x9193fd47f9a0ab99b6e365a464c8a9ae30e6150fc37ed2a89c1586631f6fc4ab",
113
- sbETH: "0x9193fd47f9a0ab99b6e365a464c8a9ae30e6150fc37ed2a89c1586631f6fc4ab",
114
- wSOL: "0x9d0d275efbd37d8a8855f6f2c761fa5983293dd8ce202ee5196626de8fcd4469",
115
- wAPT: "0x7c5b7837c44a69b469325463ac0673ac1aa8435ff44ddb4191c9ae380463647f",
116
- CETUS: "0x24c0247fb22457a719efac7f670cdc79be321b521460bd6bd2ccfa9f80713b14",
117
- TURBOS: "0x442e52f04392b0dcb48c6aaf7940568acd510281021be9f9b3a449c559c79613",
118
- SCA: "0xf6de1d3279a269a597d813cbaca59aa906543ab9a8c64e84a4722f1a20863985",
119
- SEI: "0xde2dd2684b3ff808cebdfb23afbf8b6ac3822832029dae744f81d9eb44b5c9b8",
120
- INJ: "0x353a36a5b3d6809b4cc349dca627e2775e1d19b6b9c86f0eabe138fd3d772023",
121
- AFSUI: "0xd779885c5246357e24cbde7348f2d81f756d9650975c02d81346b15d8b557ebf",
122
- NAVX: "0x5b117a6a2de70796bffe36495bad576b788a34c33ca0648bd57852ead3f41e32",
123
- HASUI: "0x4c1d831576b60fec657e0c310943eff8c1f28197c552e57d1fefdc55edddb263",
124
- VSUI: "0xf3bc79117acc3636d57778d9d0f83a871df1b7a53eb61fe893ff108d9664ec8b",
125
- DEEP: "0x8c7f3a322b94cc69db2a2ac575cbd94bf5766113324c3a3eceac91e3e88a51ed",
126
- BLUE: "0x5515a34fc610bba6b601575ed1d2535b2f9df1f339fd0d435fef487c1ee3df9c",
127
- NS: "0xc6352e1ea55d7b5acc3ed690cc3cdf8007978071d7bfd6a189445018cfb366e0",
128
- JUP: "0xb804ada6f77feb30a73fbed7fc53dc66ff25133dee0815109d4267e43b2e6bdd",
129
- WAL: "0xeb7e669f74d976c0b99b6ef9801e3a77716a95f1a15754e0f1399ce3fb60973d",
130
- LBTC: "0xeba15840ddf425dacb5ff0990334fc03d034487f4ad416280859b96bf2af89f8",
131
- XAU: "0x5b36eb3c0935908082926c0c767a55b87a2a4eb3a45908785b41f9d5a11e4f7b",
132
- XAG: "0xd5c5afce92e988bf0a0940d618443c36c31dd7f239a545982db3166e963c9aa4",
133
- USOIL: "0x71e40a6e2af5a194e149a761ae11d43e987b9ecbee1834d65d61103721c72e02",
134
- DOGE: "0xd59a5f5173424ba725a7d033d86f2eadf2745f87a908bd27e1d27339eff598ce",
135
- HYPE: "0x1c047be615eaa5a87afa0e111b20a512dd6c0f4a1f0f691693cf852c1768f35d",
136
- XRP: "0x93bfda25cb6b1653a9c769e8216014bd2c06997f3edb479566761fbf2abf6ac2",
137
- xBTC: "0xa4b9db1866ee6e2a156e8c36fc66be0f68f232388ebb578c949c2c6beb50128b",
138
- JPY: "0xde0e6088e7292f50738ecbdebd4502415d4f8de4cfe001918e29b3f4faf15baa",
139
- BNB: "0x9c6e77f0ecfc46aac395e21c52ccb96518f85acacae743c5b47f4ca5e29826c3",
140
- SPYX: "0x6a2d53a802faee96b26f5fa86d9ccf05d58008e4f32c95985d12edb60f5e23ea",
141
- QQQX: "0xcce836357b028bd85e866320f194980125b58e6117a2e86a24ed5c154df1e799",
142
- NVDAX: "0x1ccc57727035cc40a122cecd95f15240de4fb3f2acd5542c8f2109ebc47871a1",
143
- TSLAX: "0x678fee0f8d449160f7df3a14db41d7318e917c3afae98eed434a87073cb80c6b",
144
- AAPLX: "0x80c9fa9060e2682528a9b02e0facfd6c4816e1bb363bdc3c9a6e94224618e03d",
145
- GOOGLX: "0xff0bda4e0c212f409b89c6c5714c1957f6a867eced1bcfde863bd074d2a0d54c",
146
- METAX: "0x0cd398ea0262b504a946b3d4acde457a21bee9d41a27083ebf6ec19f99272155",
147
- COINX: "0xf19da6da74181c159f3619cc50fdd4dcc62d15538c707175464968a14cbb0464",
148
- CRCLX: "0x299b647faef2456b93155b5609ac5edc9ba18bb4f5f6a27383920a528b2ff052",
149
- HOODX: "0x1f0a01610d47dfe0506bb4cfd903335bf2d148adc86459c06385b97309e51d2a",
150
- MSTRX: "0xab35f27f1118959cbf82e5ab907808df40b25c16c5745c21a1af721a2e0a926e",
151
- },
152
- TESTNET: {
153
- SUI: "0x1ebb295c789cc42b3b2a1606482cd1c7124076a0f5676718501fda8c7fd075a0",
154
- CETUS: "0xb0ba78106259b7ceefd288edc5f65b65f8b7bca0816e61dae5136616aac7d3da",
155
- USDC: "0x9c4dd4008297ffa5e480684b8100ec21cc934405ed9a25d4e4d7b6259aad9c81",
156
- wUSDC: "0x9c4dd4008297ffa5e480684b8100ec21cc934405ed9a25d4e4d7b6259aad9c81",
157
- WBTC: "0x72431a238277695d3f31e4425225a4462674ee6cceeea9d66447b210755fffba",
158
- wETH: "0x4fde30cb8a5dc3cfee1c1c358fc66dc308408827efb217247c7ba54d76ccbee9",
159
- sbETH: "0x4fde30cb8a5dc3cfee1c1c358fc66dc308408827efb217247c7ba54d76ccbee9",
160
- wSOL: "0x33fbce1cad5ca155f2f5051430b23a694bc6e5de6df43e0f8aefe29f4a84336d",
161
- TURBOS: "0xfe38289883c3afed692e5856f4896b3e094d4793e2ccf0a2715b890a718fa5c0",
162
- wAPT: "0x9eeb8cb349d8e89fa9e6c94a97d6d30096f5b3c16bd50d9de96608f67a278c18",
163
- wUSDT: "0x956fdcbf83a26c962319f7742f5728a0a7ce59c7f0cbe13c112b259e7ee953cd",
164
- // DOGE: "0x17b358d730663caa888c8b621b9994a60af422cd83f32237c6b2a8b3230d71b9",
165
- INJ: "0x459e2e0dd757715449fc1d36925f384446bf192c9f86a4ca02d587c82de51802",
166
- SEI: "0xb3e7f40e8268fb2539a03b29c1b38366e061c3c8222f7ad4c8db998eb0a02f8d",
167
- JUP: "0x23817c9edbbfbdef6add3800cd52751eff5bb0f7abd32e54a8f2225d6a6523d3",
168
- SCA: "0xf96e3c4b7d74efbde9df5b669188421196e6164adf6fbaaa92903c42569807c8",
169
- AFSUI: "0x6785a8c69da40c9435d41a2585cf92643d2ed2c5cd12938ecff28eaf54efadcd",
170
- NAVX: "0x94905bdcaa656b0908aa8a3a42cf72b0e8e2e849f7d0a7e0e39bb9e1dc3c9cf6",
171
- USDY: "0x1fec4ed70f870911948d93eb2abe6fa4a3a4b1e4633cf36c7e91adfb4af1733f",
172
- BLUE: "0xcc9016bcfaf1839f1dd63b0929a0d62dfb93e84442fd5b4598552605e365b3ec",
173
- BLUB: "0xdcd4cc5f06fac1ca72e8551ab1a2e847298afa6f19e370ad9891199a59d2c22e",
174
- JPY: "0xd14cadaf54a926f701db021eceaa89b3d09363e1bce51bfcb2291a32a693f928",
175
- XAU: "0x742d48ff1d7a45c91aee4ad4f0059396c28988f99074d4a191951ac086b90a5a",
176
- XAG: "",
177
- USOIL: "",
178
- xBTC: "0xb6c3b17fdda1eaa847e62c8d36a8dada35b010bb340fdb5a16d556f0fa37e59b",
179
- },
180
- };
181
- // Get the state IDs of the Pyth and Wormhole contracts from
182
- // https://docs.pyth.network/price-feeds/contract-addresses/sui
183
- exports.wormholeStateId = {
184
- MAINNET: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
185
- TESTNET: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
186
- };
187
- exports.pythStateId = {
188
- MAINNET: "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8",
189
- TESTNET: "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c",
190
- };
191
- // Get the Stable Hermes service URL from https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes
192
- exports.endpoint = {
193
- MAINNET: "https://hermes.pyth.network",
194
- TESTNET: "https://hermes-beta.pyth.network",
76
+ // Pyth Lazer State object IDs on Sui.
77
+ // Source: https://docs.pyth.network/price-feeds/pro/contract-addresses
78
+ exports.lazerStateId = {
79
+ MAINNET: "0xd0db9c1e9212a98120384bf78d8b8c985d87b9ee6921dffcf9d1394062911573",
80
+ TESTNET: "0x7b570126bfdcc7f7b2b4028445d4ac1d35c41da498606a2b097c3973425698d3",
195
81
  };
@@ -1,22 +1,80 @@
1
- import { HexString, SuiPriceServiceConnection, SuiPythClient } from "@pythnetwork/pyth-sui-js";
2
- import { Argument, Transaction } from "@mysten/sui/transactions";
1
+ import type { PythLazerClient, Channel } from "@pythnetwork/pyth-lazer-sdk";
2
+ import { SuiJsonRpcClient } from "@mysten/sui/jsonRpc";
3
+ import { Transaction, type TransactionResult } from "@mysten/sui/transactions";
3
4
  import { TOKEN } from "../../../src/constants";
4
- import { ObjectId } from "@pythnetwork/pyth-sui-js/lib/client";
5
- export declare class PythClient {
5
+ export type MoveApiVersion = "v1" | "v2";
6
+ export interface PythLazerSuiClientOpts {
7
+ /**
8
+ * Long-lived-key source (WebSocket). Node-side crankers and scripts pass
9
+ * this. Do NOT use it in a browser — the key would ship in the bundle.
10
+ */
11
+ lazer?: PythLazerClient;
12
+ /**
13
+ * Client-safe alternative: returns a short-lived Pyth JWT per call, and
14
+ * price fetches go over REST instead of the WS. The JWT is accepted on
15
+ * `POST /v1/latest_price` and `/v1/price` (verified against mainnet), and
16
+ * that host sends `access-control-allow-origin: *`, so the browser can call
17
+ * it directly. Takes precedence over `lazer` when both are supplied.
18
+ */
19
+ getAccessToken?: () => string | Promise<string>;
20
+ restEndpoint?: string;
21
+ channel?: Channel;
22
+ /** Which Lazer Move API to call. See DEFAULT_MOVE_API. */
23
+ moveApiVersion?: MoveApiVersion;
24
+ sui: SuiJsonRpcClient;
6
25
  network: "MAINNET" | "TESTNET";
7
- client: SuiPythClient;
8
- connection: SuiPriceServiceConnection;
26
+ lazerPackage: string;
27
+ oraclePackage: string;
28
+ oracleV2Id: string;
29
+ stateObjectId?: string;
30
+ }
31
+ export declare class PythLazerSuiClient {
32
+ readonly lazer?: PythLazerClient;
33
+ readonly getAccessToken?: () => string | Promise<string>;
34
+ readonly restEndpoint: string;
35
+ readonly channel: Channel;
36
+ readonly moveApiVersion: MoveApiVersion;
37
+ readonly sui: SuiJsonRpcClient;
38
+ readonly network: "MAINNET" | "TESTNET";
39
+ readonly stateObjectId: string;
40
+ readonly lazerPackage: string;
41
+ readonly oraclePackage: string;
42
+ readonly oracleV2Id: string;
43
+ constructor(opts: PythLazerSuiClientOpts);
44
+ /** `_v2` suffix on the Lazer/oracle entries when on the v2 Move API. */
45
+ private get v();
46
+ /**
47
+ * Fetches a signed `leEcdsa` update over REST using a short-lived token.
48
+ * Mirrors typus-rust `lazer_ingestion::rest_client`.
49
+ */
50
+ private fetchUpdateOverRest;
51
+ private resolveFeedIds;
52
+ private resolveTypeArgument;
53
+ /**
54
+ * Fetches a Pyth Lazer `leEcdsa` update covering every requested token, adds
55
+ * `pyth_lazer::parse_and_verify_le_ecdsa_update` to the PTB, and returns the
56
+ * verified `Update` argument for use in subsequent move calls.
57
+ */
58
+ updatePythLazer(tx: Transaction, tokens: TOKEN[], timestamp?: number): Promise<TransactionResult>;
59
+ /**
60
+ * Calls `oracle_v2::update_latest_price(oracle_v2, update, clock)`. A single
61
+ * call updates every feed in the verified update.
62
+ */
63
+ updateOracleV2WithPythLazer(tx: Transaction, tokens: TOKEN[]): Promise<void>;
64
+ /**
65
+ * Calls `oracle_v2::update_settle_price(oracle_v2, update, timestamp, clock)`.
66
+ * Authority-gated on-chain. `timestamp` is in seconds.
67
+ */
68
+ updateOracleV2SettlePriceWithPythLazer(tx: Transaction, tokens: TOKEN[], timestamp: number): Promise<void>;
69
+ /**
70
+ * Calls `oracle_v2::add_latest_price_new_token<TOKEN>(oracle_v2, feed_id, update, clock)`.
71
+ * One-shot initializer for a brand-new token in the oracle's `feed_id_map`.
72
+ */
73
+ addLatestPriceNewToken(tx: Transaction, token: TOKEN, tokenTypeArgument?: string): Promise<void>;
74
+ /**
75
+ * Calls `oracle_v2::add_settle_price_new_token<TOKEN>(oracle_v2, feed_id, update, timestamp, clock)`.
76
+ * `timestamp` (seconds) is forwarded to the Lazer fetch when supplied and
77
+ * passed on-chain; defaults to now, matching the freshness window.
78
+ */
79
+ addSettlePriceNewToken(tx: Transaction, token: TOKEN, timestamp?: number, tokenTypeArgument?: string): Promise<void>;
9
80
  }
10
- export declare function createPythClient(provider: any, network: "MAINNET" | "TESTNET"): PythClient;
11
- /**
12
- * @returns priceInfoObjectIds
13
- */
14
- export declare function updatePyth(pythClient: PythClient, tx: Transaction, tokens: TOKEN[], suiCoin?: Argument): Promise<ObjectId[]>;
15
- export declare function updateOracleWithPythUsd(pythClient: PythClient, tx: Transaction, oraclePackage: string, baseToken: TOKEN): void;
16
- /**
17
- * Adds the necessary commands for updating the pyth price feeds to the transaction block.
18
- * @param tx transaction block to add commands to
19
- * @param updates array of price feed updates received from the price service
20
- * @param feedIds array of feed ids to update (in hex format)
21
- */
22
- export declare function updatePriceFeeds(pythClient: PythClient, tx: Transaction, updates: Buffer[], feedIds: HexString[], suiCoin?: Argument): Promise<ObjectId[]>;
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -36,81 +47,259 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
36
47
  }
37
48
  };
38
49
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.createPythClient = createPythClient;
40
- exports.updatePyth = updatePyth;
41
- exports.updateOracleWithPythUsd = updateOracleWithPythUsd;
42
- exports.updatePriceFeeds = updatePriceFeeds;
43
- var pyth_sui_js_1 = require("@pythnetwork/pyth-sui-js");
44
- var constant_1 = require("./constant");
50
+ exports.PythLazerSuiClient = void 0;
45
51
  var constants_1 = require("../../../src/constants");
46
- function createPythClient(provider, network) {
47
- var client = new pyth_sui_js_1.SuiPythClient(provider, constant_1.pythStateId[network], constant_1.wormholeStateId[network]);
48
- var connection = network == "MAINNET"
49
- ? new pyth_sui_js_1.SuiPriceServiceConnection("https://hermes.pyth.network")
50
- : new pyth_sui_js_1.SuiPriceServiceConnection("https://hermes-beta.pyth.network");
51
- var pythClient = { network: network, client: client, connection: connection };
52
- return pythClient;
53
- }
54
- /**
55
- * @returns priceInfoObjectIds
56
- */
57
- function updatePyth(pythClient, tx, tokens, suiCoin) {
58
- return __awaiter(this, void 0, void 0, function () {
59
- var _priceIDs, priceFeedUpdateData, priceInfoObjectIds;
60
- return __generator(this, function (_a) {
61
- switch (_a.label) {
62
- case 0:
63
- _priceIDs = tokens.map(function (token) { return constant_1.priceIDs[pythClient.network][token]; });
64
- return [4 /*yield*/, pythClient.connection.getPriceFeedsUpdateData(_priceIDs)];
65
- case 1:
66
- priceFeedUpdateData = _a.sent();
67
- return [4 /*yield*/, updatePriceFeeds(pythClient, tx, priceFeedUpdateData, _priceIDs, suiCoin)];
68
- case 2:
69
- priceInfoObjectIds = _a.sent();
70
- return [2 /*return*/, priceInfoObjectIds];
71
- }
72
- });
73
- });
74
- }
75
- function updateOracleWithPythUsd(pythClient, tx, oraclePackage, baseToken) {
76
- tx.moveCall({
77
- target: "".concat(oraclePackage, "::oracle::update_with_pyth_usd"),
78
- typeArguments: [],
79
- arguments: [
80
- tx.object(constants_1.oracle[pythClient.network][baseToken]),
81
- tx.object(constant_1.pythStateId[pythClient.network]),
82
- tx.object(constant_1.priceInfoObjectIds[pythClient.network][baseToken]),
83
- tx.object("0x6"),
84
- ],
52
+ var constant_1 = require("./constant");
53
+ var DEFAULT_PROPERTIES = ["price", "emaPrice", "exponent", "feedUpdateTimestamp"];
54
+ // The mainnet oracle reads `fixed_rate@1000ms`, and that channel is only served
55
+ // by the Lazer *v2* Move API (`..._v2` entries) — the v1 entries are pinned to
56
+ // the 200ms channel. Changing one without the other aborts on-chain.
57
+ var DEFAULT_CHANNEL = "fixed_rate@1000ms";
58
+ var DEFAULT_MOVE_API = "v2";
59
+ // Signed (`leEcdsa`) payloads come from the legacy Lazer host, not the Pro `/v1`
60
+ // API — the Pro OpenAPI exposes no signed-payload route at all.
61
+ var DEFAULT_REST_ENDPOINT = "https://pyth-lazer-0.dourolabs.app";
62
+ /** Browser-safe: hex -> bytes without Node's Buffer. */
63
+ var hexToBytes = function (hex) {
64
+ var clean = hex.startsWith("0x") ? hex.slice(2) : hex;
65
+ if (clean.length % 2 !== 0) {
66
+ throw new Error("Pyth Lazer leEcdsa payload is not valid hex (odd length)");
67
+ }
68
+ var out = new Uint8Array(clean.length / 2);
69
+ for (var i = 0; i < out.length; i++) {
70
+ out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
71
+ }
72
+ return out;
73
+ };
74
+ var PythLazerSuiClient = /** @class */ (function () {
75
+ function PythLazerSuiClient(opts) {
76
+ var _a, _b, _c, _d;
77
+ this.lazer = opts.lazer;
78
+ this.getAccessToken = opts.getAccessToken;
79
+ // A missing price source is only fatal when a price is actually fetched
80
+ // — plenty of callers construct a client purely for read-only views.
81
+ this.restEndpoint = ((_a = opts.restEndpoint) !== null && _a !== void 0 ? _a : DEFAULT_REST_ENDPOINT).replace(/\/+$/, "");
82
+ this.channel = (_b = opts.channel) !== null && _b !== void 0 ? _b : DEFAULT_CHANNEL;
83
+ this.moveApiVersion = (_c = opts.moveApiVersion) !== null && _c !== void 0 ? _c : DEFAULT_MOVE_API;
84
+ this.sui = opts.sui;
85
+ this.network = opts.network;
86
+ this.lazerPackage = opts.lazerPackage;
87
+ this.oraclePackage = opts.oraclePackage;
88
+ this.oracleV2Id = opts.oracleV2Id;
89
+ this.stateObjectId = (_d = opts.stateObjectId) !== null && _d !== void 0 ? _d : constant_1.lazerStateId[opts.network];
90
+ if (!this.stateObjectId) {
91
+ throw new Error("No Pyth Lazer state object id mapped for ".concat(opts.network));
92
+ }
93
+ }
94
+ Object.defineProperty(PythLazerSuiClient.prototype, "v", {
95
+ /** `_v2` suffix on the Lazer/oracle entries when on the v2 Move API. */
96
+ get: function () {
97
+ return this.moveApiVersion === "v2" ? "_v2" : "";
98
+ },
99
+ enumerable: false,
100
+ configurable: true
85
101
  });
86
- }
87
- /**
88
- * Adds the necessary commands for updating the pyth price feeds to the transaction block.
89
- * @param tx transaction block to add commands to
90
- * @param updates array of price feed updates received from the price service
91
- * @param feedIds array of feed ids to update (in hex format)
92
- */
93
- function updatePriceFeeds(pythClient, tx, updates, feedIds, suiCoin) {
94
- return __awaiter(this, void 0, void 0, function () {
95
- var packageId, priceUpdatesHotPotato, baseUpdateFee, coins;
96
- return __generator(this, function (_a) {
97
- switch (_a.label) {
98
- case 0: return [4 /*yield*/, pythClient.client.getPythPackageId()];
99
- case 1:
100
- packageId = _a.sent();
101
- return [4 /*yield*/, pythClient.client.verifyVaasAndGetHotPotato(tx, updates, packageId)];
102
- case 2:
103
- priceUpdatesHotPotato = _a.sent();
104
- return [4 /*yield*/, pythClient.client.getBaseUpdateFee()];
105
- case 3:
106
- baseUpdateFee = _a.sent();
107
- coins = tx.splitCoins(suiCoin !== null && suiCoin !== void 0 ? suiCoin : tx.gas, feedIds.map(function () { return tx.pure.u64(baseUpdateFee); }));
108
- if (suiCoin) {
109
- tx.moveCall({ target: "0x2::coin::destroy_zero", arguments: [suiCoin], typeArguments: [constants_1.tokenType.MAINNET.SUI] });
110
- }
111
- return [4 /*yield*/, pythClient.client.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins)];
112
- case 4: return [2 /*return*/, _a.sent()];
102
+ /**
103
+ * Fetches a signed `leEcdsa` update over REST using a short-lived token.
104
+ * Mirrors typus-rust `lazer_ingestion::rest_client`.
105
+ */
106
+ PythLazerSuiClient.prototype.fetchUpdateOverRest = function (priceFeedIds, timestamp) {
107
+ return __awaiter(this, void 0, void 0, function () {
108
+ var token, path, res, _a, _b, _c;
109
+ return __generator(this, function (_d) {
110
+ switch (_d.label) {
111
+ case 0: return [4 /*yield*/, this.getAccessToken()];
112
+ case 1:
113
+ token = _d.sent();
114
+ path = timestamp ? "v1/price" : "v1/latest_price";
115
+ return [4 /*yield*/, fetch("".concat(this.restEndpoint, "/").concat(path), {
116
+ method: "POST",
117
+ headers: { Authorization: "Bearer ".concat(token), "Content-Type": "application/json" },
118
+ body: JSON.stringify(__assign({ priceFeedIds: priceFeedIds, properties: DEFAULT_PROPERTIES, formats: ["leEcdsa"], jsonBinaryEncoding: "hex", channel: this.channel }, (timestamp ? { timestamp: timestamp * 1000000 } : {}))),
119
+ })];
120
+ case 2:
121
+ res = _d.sent();
122
+ if (!!res.ok) return [3 /*break*/, 4];
123
+ _a = Error.bind;
124
+ _c = (_b = "Pyth Lazer ".concat(path, " ").concat(res.status, ": ")).concat;
125
+ return [4 /*yield*/, res.text()];
126
+ case 3: throw new (_a.apply(Error, [void 0, _c.apply(_b, [_d.sent()])]))();
127
+ case 4: return [4 /*yield*/, res.json()];
128
+ case 5: return [2 /*return*/, (_d.sent())];
129
+ }
130
+ });
131
+ });
132
+ };
133
+ PythLazerSuiClient.prototype.resolveFeedIds = function (tokens) {
134
+ return tokens.map(function (token) {
135
+ var id = constant_1.feedIds[token];
136
+ if (id == null) {
137
+ throw new Error("No Pyth Lazer feed id mapped for token ".concat(token));
113
138
  }
139
+ return id;
114
140
  });
115
- });
116
- }
141
+ };
142
+ PythLazerSuiClient.prototype.resolveTypeArgument = function (token, override) {
143
+ var typeArg = override !== null && override !== void 0 ? override : constants_1.tokenType[this.network][token];
144
+ if (!typeArg) {
145
+ throw new Error("No coin type mapped for ".concat(token, " on ").concat(this.network));
146
+ }
147
+ return typeArg;
148
+ };
149
+ /**
150
+ * Fetches a Pyth Lazer `leEcdsa` update covering every requested token, adds
151
+ * `pyth_lazer::parse_and_verify_le_ecdsa_update` to the PTB, and returns the
152
+ * verified `Update` argument for use in subsequent move calls.
153
+ */
154
+ PythLazerSuiClient.prototype.updatePythLazer = function (tx, tokens, timestamp) {
155
+ return __awaiter(this, void 0, void 0, function () {
156
+ var priceFeedIds, update, hex, u8array;
157
+ var _a;
158
+ return __generator(this, function (_b) {
159
+ switch (_b.label) {
160
+ case 0:
161
+ priceFeedIds = this.resolveFeedIds(tokens);
162
+ if (!this.lazer && !this.getAccessToken) {
163
+ throw new Error("PythLazerSuiClient needs either `lazer` (WS) or `getAccessToken` (REST) to fetch prices");
164
+ }
165
+ if (!this.getAccessToken) return [3 /*break*/, 2];
166
+ return [4 /*yield*/, this.fetchUpdateOverRest(priceFeedIds, timestamp)];
167
+ case 1:
168
+ update = _b.sent();
169
+ return [3 /*break*/, 6];
170
+ case 2:
171
+ if (!timestamp) return [3 /*break*/, 4];
172
+ return [4 /*yield*/, this.lazer.getPrice({
173
+ priceFeedIds: priceFeedIds,
174
+ properties: DEFAULT_PROPERTIES,
175
+ formats: ["leEcdsa"],
176
+ jsonBinaryEncoding: "hex",
177
+ channel: this.channel,
178
+ timestamp: timestamp * 1000000, // seconds -> nanoseconds
179
+ })];
180
+ case 3:
181
+ update = _b.sent();
182
+ return [3 /*break*/, 6];
183
+ case 4: return [4 /*yield*/, this.lazer.getLatestPrice({
184
+ priceFeedIds: priceFeedIds,
185
+ properties: DEFAULT_PROPERTIES,
186
+ formats: ["leEcdsa"],
187
+ jsonBinaryEncoding: "hex",
188
+ channel: this.channel,
189
+ })];
190
+ case 5:
191
+ update = _b.sent();
192
+ _b.label = 6;
193
+ case 6:
194
+ hex = (_a = update.leEcdsa) === null || _a === void 0 ? void 0 : _a.data;
195
+ if (!hex) {
196
+ throw new Error("Pyth Lazer getLatestPrice returned no leEcdsa payload");
197
+ }
198
+ u8array = hexToBytes(hex);
199
+ return [2 /*return*/, tx.moveCall({
200
+ target: "".concat(this.lazerPackage, "::pyth_lazer::parse_and_verify_le_ecdsa_update").concat(this.v),
201
+ arguments: [tx.object(this.stateObjectId), tx.object.clock(), tx.pure.vector("u8", u8array)],
202
+ })];
203
+ }
204
+ });
205
+ });
206
+ };
207
+ /**
208
+ * Calls `oracle_v2::update_latest_price(oracle_v2, update, clock)`. A single
209
+ * call updates every feed in the verified update.
210
+ */
211
+ PythLazerSuiClient.prototype.updateOracleV2WithPythLazer = function (tx, tokens) {
212
+ return __awaiter(this, void 0, void 0, function () {
213
+ var verifiedUpdate;
214
+ return __generator(this, function (_a) {
215
+ switch (_a.label) {
216
+ case 0: return [4 /*yield*/, this.updatePythLazer(tx, tokens)];
217
+ case 1:
218
+ verifiedUpdate = _a.sent();
219
+ tx.moveCall({
220
+ target: "".concat(this.oraclePackage, "::oracle_v2::update_latest_price").concat(this.v),
221
+ typeArguments: [],
222
+ arguments: [tx.object(this.oracleV2Id), verifiedUpdate, tx.object("0x6")],
223
+ });
224
+ return [2 /*return*/];
225
+ }
226
+ });
227
+ });
228
+ };
229
+ /**
230
+ * Calls `oracle_v2::update_settle_price(oracle_v2, update, timestamp, clock)`.
231
+ * Authority-gated on-chain. `timestamp` is in seconds.
232
+ */
233
+ PythLazerSuiClient.prototype.updateOracleV2SettlePriceWithPythLazer = function (tx, tokens, timestamp) {
234
+ return __awaiter(this, void 0, void 0, function () {
235
+ var verifiedUpdate;
236
+ return __generator(this, function (_a) {
237
+ switch (_a.label) {
238
+ case 0: return [4 /*yield*/, this.updatePythLazer(tx, tokens, timestamp)];
239
+ case 1:
240
+ verifiedUpdate = _a.sent();
241
+ tx.moveCall({
242
+ target: "".concat(this.oraclePackage, "::oracle_v2::update_settle_price").concat(this.v),
243
+ typeArguments: [],
244
+ arguments: [tx.object(this.oracleV2Id), verifiedUpdate, tx.pure.u64(timestamp), tx.object("0x6")],
245
+ });
246
+ return [2 /*return*/];
247
+ }
248
+ });
249
+ });
250
+ };
251
+ /**
252
+ * Calls `oracle_v2::add_latest_price_new_token<TOKEN>(oracle_v2, feed_id, update, clock)`.
253
+ * One-shot initializer for a brand-new token in the oracle's `feed_id_map`.
254
+ */
255
+ PythLazerSuiClient.prototype.addLatestPriceNewToken = function (tx, token, tokenTypeArgument) {
256
+ return __awaiter(this, void 0, void 0, function () {
257
+ var feedId, typeArg, verifiedUpdate;
258
+ return __generator(this, function (_a) {
259
+ switch (_a.label) {
260
+ case 0:
261
+ feedId = this.resolveFeedIds([token])[0];
262
+ typeArg = this.resolveTypeArgument(token, tokenTypeArgument);
263
+ return [4 /*yield*/, this.updatePythLazer(tx, [token])];
264
+ case 1:
265
+ verifiedUpdate = _a.sent();
266
+ tx.moveCall({
267
+ target: "".concat(this.oraclePackage, "::oracle_v2::add_latest_price_new_token").concat(this.v),
268
+ typeArguments: [typeArg],
269
+ arguments: [tx.object(this.oracleV2Id), tx.pure.u32(feedId), verifiedUpdate, tx.object("0x6")],
270
+ });
271
+ return [2 /*return*/];
272
+ }
273
+ });
274
+ });
275
+ };
276
+ /**
277
+ * Calls `oracle_v2::add_settle_price_new_token<TOKEN>(oracle_v2, feed_id, update, timestamp, clock)`.
278
+ * `timestamp` (seconds) is forwarded to the Lazer fetch when supplied and
279
+ * passed on-chain; defaults to now, matching the freshness window.
280
+ */
281
+ PythLazerSuiClient.prototype.addSettlePriceNewToken = function (tx, token, timestamp, tokenTypeArgument) {
282
+ return __awaiter(this, void 0, void 0, function () {
283
+ var feedId, typeArg, ts, verifiedUpdate;
284
+ return __generator(this, function (_a) {
285
+ switch (_a.label) {
286
+ case 0:
287
+ feedId = this.resolveFeedIds([token])[0];
288
+ typeArg = this.resolveTypeArgument(token, tokenTypeArgument);
289
+ ts = timestamp !== null && timestamp !== void 0 ? timestamp : Math.floor(Date.now() / 1000);
290
+ return [4 /*yield*/, this.updatePythLazer(tx, [token], timestamp)];
291
+ case 1:
292
+ verifiedUpdate = _a.sent();
293
+ tx.moveCall({
294
+ target: "".concat(this.oraclePackage, "::oracle_v2::add_settle_price_new_token").concat(this.v),
295
+ typeArguments: [typeArg],
296
+ arguments: [tx.object(this.oracleV2Id), tx.pure.u32(feedId), verifiedUpdate, tx.pure.u64(ts), tx.object("0x6")],
297
+ });
298
+ return [2 /*return*/];
299
+ }
300
+ });
301
+ });
302
+ };
303
+ return PythLazerSuiClient;
304
+ }());
305
+ exports.PythLazerSuiClient = PythLazerSuiClient;
package/package.json CHANGED
@@ -2,12 +2,13 @@
2
2
  "name": "@typus/typus-sdk",
3
3
  "author": "Typus",
4
4
  "description": "typus sdk",
5
- "version": "1.9.4",
5
+ "version": "1.10.1",
6
6
  "dependencies": {
7
7
  "@mysten/bcs": "2.0.3",
8
8
  "@mysten/kiosk": "1.2.0",
9
9
  "@mysten/sui": "2.13.2",
10
- "@pythnetwork/pyth-sui-js": "2.3.0",
10
+ "@pythnetwork/pyth-lazer-sdk": "6.2.2",
11
+ "@pythnetwork/pyth-lazer-sui-js": "0.3.0",
11
12
  "@shinami/clients": "0.10.0",
12
13
  "bignumber.js": "^9.1.2",
13
14
  "camelcase-keys-deep": "^0.1.0",
@@ -51,4 +52,4 @@
51
52
  "url": "https://github.com/Typus-Lab/typus-sdk/issues"
52
53
  },
53
54
  "homepage": "https://github.com/Typus-Lab/typus-sdk#readme"
54
- }
55
+ }