@naviprotocol/lending 2.0.7 → 2.0.8
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.
- package/dist/oracle.d.ts +7 -2
- package/dist/oracle.d.ts.map +1 -1
- package/dist/oracle.js +6 -4
- package/dist/oracle.js.map +1 -1
- package/dist/package.json.js +1 -1
- package/dist/pyth.d.ts +4 -2
- package/dist/pyth.d.ts.map +1 -1
- package/dist/pyth.js +54 -54
- package/dist/pyth.js.map +1 -1
- package/package.json +1 -1
package/dist/oracle.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OraclePriceFeed, EnvOption, UserLendingInfo, Pool, SuiClientOption, MarketOption, LendingPosition, ServiceOption } from './types.js';
|
|
1
|
+
import { OraclePriceFeed, EnvOption, UserLendingInfo, Pool, SuiClientOption, MarketOption, LendingPosition, ServiceOption, TransactionObjectArgument } from './types.js';
|
|
2
2
|
import { Transaction } from '@mysten/sui/transactions';
|
|
3
3
|
|
|
4
4
|
type PythInfo = {
|
|
@@ -38,7 +38,9 @@ export declare function getPythStalePriceFeedIdV2(pythInfos: PythInfo[], options
|
|
|
38
38
|
* @returns Promise that resolves when price feeds are updated
|
|
39
39
|
* @throws Error if failed to update price feeds
|
|
40
40
|
*/
|
|
41
|
-
export declare function updatePythPriceFeeds(tx: Transaction, priceFeedIds: string[], options?: Partial<SuiClientOption & EnvOption & MarketOption
|
|
41
|
+
export declare function updatePythPriceFeeds(tx: Transaction, priceFeedIds: string[], options?: Partial<SuiClientOption & EnvOption & MarketOption & {
|
|
42
|
+
pythFeeCoin?: TransactionObjectArgument;
|
|
43
|
+
}>): Promise<string[]>;
|
|
42
44
|
/**
|
|
43
45
|
* Update oracle prices in the PTB (Programmable Transaction Block)
|
|
44
46
|
*
|
|
@@ -53,6 +55,8 @@ export declare function updatePythPriceFeeds(tx: Transaction, priceFeedIds: stri
|
|
|
53
55
|
*/
|
|
54
56
|
export declare function updateOraclePricesPTB(tx: Transaction, priceFeeds: OraclePriceFeed[], options?: Partial<EnvOption & SuiClientOption & ServiceOption & MarketOption & {
|
|
55
57
|
updatePythPriceFeeds?: boolean;
|
|
58
|
+
/** Optional user-owned SUI coin used for Pyth update fees. Defaults to `tx.gas`. */
|
|
59
|
+
pythFeeCoin?: TransactionObjectArgument;
|
|
56
60
|
}>): Promise<Transaction>;
|
|
57
61
|
/**
|
|
58
62
|
* Get all available price feeds from the configuration
|
|
@@ -78,6 +82,7 @@ export declare function filterPriceFeeds(feeds: OraclePriceFeed[], filters: {
|
|
|
78
82
|
}): OraclePriceFeed[];
|
|
79
83
|
export declare function updateOraclePriceBeforeUserOperationPTB(tx: Transaction, address: string, pools: Pool[], options?: Partial<EnvOption & SuiClientOption & MarketOption & {
|
|
80
84
|
throws?: boolean;
|
|
85
|
+
pythFeeCoin?: TransactionObjectArgument;
|
|
81
86
|
}>): Promise<Transaction>;
|
|
82
87
|
export {};
|
|
83
88
|
//# sourceMappingURL=oracle.d.ts.map
|
package/dist/oracle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oracle.d.ts","sourceRoot":"","sources":["../src/oracle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EACV,eAAe,EACf,SAAS,EACT,eAAe,EACf,IAAI,EACJ,eAAe,EACf,YAAY,EACZ,eAAe,EACf,aAAa,
|
|
1
|
+
{"version":3,"file":"oracle.d.ts","sourceRoot":"","sources":["../src/oracle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EACV,eAAe,EACf,SAAS,EACT,eAAe,EACf,IAAI,EACJ,eAAe,EACf,YAAY,EACZ,eAAe,EACf,aAAa,EACb,yBAAyB,EAC1B,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAItD,KAAK,QAAQ,GAAG;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAiBD;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,GAC1C,OAAO,CAAC,MAAM,EAAE,CAAC,CA+BnB;AA4DD,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,QAAQ,EAAE,EACrB,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,WAAW,EACf,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE,OAAO,CACf,eAAe,GACb,SAAS,GACT,YAAY,GAAG;IACb,WAAW,CAAC,EAAE,yBAAyB,CAAA;CACxC,CACJ,qBAuBF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,WAAW,EACf,UAAU,EAAE,eAAe,EAAE,EAC7B,OAAO,CAAC,EAAE,OAAO,CACf,SAAS,GACP,eAAe,GACf,aAAa,GACb,YAAY,GAAG;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,oFAAoF;IACpF,WAAW,CAAC,EAAE,yBAAyB,CAAA;CACxC,CACJ,GACA,OAAO,CAAC,WAAW,CAAC,CA0CtB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,aAAa,CAAC,GAC3C,OAAO,CAAC,eAAe,EAAE,CAAC,CAM5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,eAAe,EAAE,EACxB,OAAO,EAAE;IACP,YAAY,CAAC,EAAE,eAAe,EAAE,CAAA;IAChC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAA;CACrC,GACA,eAAe,EAAE,CA0CnB;AAED,wBAAsB,uCAAuC,CAC3D,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,CAAC,EAAE,OAAO,CACf,SAAS,GACP,eAAe,GACf,YAAY,GAAG;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,yBAAyB,CAAA;CACxC,CACJ,wBAqDF"}
|
package/dist/oracle.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getConfig as p, DEFAULT_CACHE_TIME as l } from "./config.js";
|
|
2
|
-
import { SuiPythClient as
|
|
2
|
+
import { SuiPythClient as F, SuiPriceServiceConnection as j } from "./pyth.js";
|
|
3
3
|
import { suiClient as b, multiGetSuiObjects as T } from "./utils.js";
|
|
4
4
|
import { getLendingPositions as O } from "./account.js";
|
|
5
5
|
const h = /* @__PURE__ */ new Map(), y = (i) => {
|
|
6
6
|
const c = i ?? "https://hermes.pyth.network";
|
|
7
7
|
let e = h.get(c);
|
|
8
|
-
return e || (e = new
|
|
8
|
+
return e || (e = new j(c, { timeout: 1e4 }), h.set(c, e)), e;
|
|
9
9
|
};
|
|
10
10
|
async function A(i, c) {
|
|
11
11
|
try {
|
|
@@ -95,11 +95,13 @@ async function C(i, c, e) {
|
|
|
95
95
|
const n = await y(
|
|
96
96
|
t.oracle.hermesEndpoint
|
|
97
97
|
).getPriceFeedsUpdateData(c);
|
|
98
|
-
return await new
|
|
98
|
+
return await new F(
|
|
99
99
|
o,
|
|
100
100
|
t.oracle.pythStateId,
|
|
101
101
|
t.oracle.wormholeStateId
|
|
102
|
-
).updatePriceFeeds(i, n, c
|
|
102
|
+
).updatePriceFeeds(i, n, c, {
|
|
103
|
+
feeCoin: e?.pythFeeCoin
|
|
104
|
+
});
|
|
103
105
|
} catch (n) {
|
|
104
106
|
throw new Error(`failed to update pyth price feeds, msg: ${n.message}`);
|
|
105
107
|
}
|
package/dist/oracle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oracle.js","sources":["../src/oracle.ts"],"sourcesContent":["/**\n * Oracle Price Feed Management for Lending Protocol\n *\n * This module provides oracle price feed functionality for the lending protocol.\n * It integrates with Pyth Network for real-time price data and manages price updates\n * for various assets used in lending operations.\n */\n\nimport { getConfig, DEFAULT_CACHE_TIME } from './config'\nimport type {\n OraclePriceFeed,\n EnvOption,\n UserLendingInfo,\n Pool,\n SuiClientOption,\n MarketOption,\n LendingPosition,\n ServiceOption\n} from './types'\nimport { SuiPriceServiceConnection, SuiPythClient } from './pyth'\nimport { Transaction } from '@mysten/sui/transactions'\nimport { multiGetSuiObjects, suiClient } from './utils'\nimport { getLendingPositions } from './account'\n\ntype PythInfo = {\n priceFeedId: string\n priceInfoObject: string\n expiration?: number\n}\n\nexport type PythPriceInfo = {\n priceFeedId: string\n priceInfoObject: string\n price: string\n conf: string\n publishTime: number\n expiration?: number\n}\n\n/**\n * Pyth Network connection for price feed data\n * Connects to the Hermes endpoint for real-time price updates\n */\nconst pythConnections = new Map<string, SuiPriceServiceConnection>()\nconst getPythConnection = (endpoint?: string) => {\n const url = endpoint ?? 'https://hermes.pyth.network'\n let conn = pythConnections.get(url)\n if (!conn) {\n conn = new SuiPriceServiceConnection(url, { timeout: 10000 })\n pythConnections.set(url, conn)\n }\n return conn\n}\n\n/**\n * Get stale price feed IDs from Pyth Network\n *\n * Identifies price feeds that have not been updated recently (more than 30 seconds old).\n * This helps ensure that only fresh price data is used for lending operations.\n *\n * @param priceIds - Array of Pyth price feed IDs to check\n * @returns Array of stale price feed IDs that need updating\n * @throws Error if failed to fetch price feed data\n */\nexport async function getPythStalePriceFeedId(\n priceIds: string[],\n options?: Partial<EnvOption & MarketOption>\n): Promise<string[]> {\n try {\n const returnData: string[] = []\n const config = await getConfig({ ...options, cacheTime: DEFAULT_CACHE_TIME })\n const latestPriceFeeds = await getPythConnection(\n config.oracle.hermesEndpoint\n ).getLatestPriceFeeds(priceIds)\n if (!latestPriceFeeds) return returnData\n\n const currentTimestamp = Math.floor(new Date().valueOf() / 1000)\n for (const priceFeed of latestPriceFeeds) {\n const uncheckedPrice = priceFeed.getPriceUnchecked()\n if (uncheckedPrice.publishTime > currentTimestamp) {\n console.warn(\n `pyth price feed is invalid, id: ${priceFeed.id}, publish time: ${uncheckedPrice.publishTime}, current timestamp: ${currentTimestamp}`\n )\n continue\n }\n\n // From pyth state is 60, but setting it to 30 makes more sense.\n if (currentTimestamp - priceFeed.getPriceUnchecked().publishTime > 30) {\n console.info(\n `stale price feed, id: ${priceFeed.id}, publish time: ${uncheckedPrice.publishTime}, current timestamp: ${currentTimestamp}`\n )\n returnData.push(priceFeed.id)\n }\n }\n return returnData\n } catch (error) {\n throw new Error(`failed to get pyth stale price feed id, msg: ${(error as Error).message}`)\n }\n}\n\nasync function getOnChainPriceInfo(\n pythInfos: PythInfo[],\n options?: Partial<SuiClientOption>\n): Promise<PythPriceInfo[]> {\n // Whole-read failures (endpoint/RPC errors) propagate to the caller:\n // swallowing them here would silently skip the Pyth staleness update and let\n // transactions build against stale on-chain prices. Only per-feed anomalies\n // are skipped below.\n const priceInfos: PythPriceInfo[] = []\n const client = options?.client ?? suiClient\n\n const priceInfoObjectIds = pythInfos.map((k) => k.priceInfoObject)\n const priceInfoObjects = await multiGetSuiObjects(client, {\n ids: Array.from(new Set(priceInfoObjectIds)),\n options: { showContent: true }\n })\n for (const obj of priceInfoObjects) {\n const data = obj.data\n if (!data || !data.content || data.content.dataType !== 'moveObject') {\n console.warn(`fetched object ${data?.objectId} datatype should be moveObject`)\n continue\n }\n\n const pythInfo = pythInfos.find((v) => v.priceInfoObject == data.objectId)\n if (!pythInfo) {\n console.warn(`unable to find pyth info from array, priceInfoObject: ${data.objectId}`)\n continue\n }\n\n // The Sui v2 client returns nested Move structs directly, without the\n // per-level `.fields` wrapper the legacy JSON-RPC object shape carried.\n // Read the flattened shape and skip (not throw) on an unexpected object so\n // a single malformed feed can't abort the whole batch and silently leave\n // every on-chain price un-refreshed.\n // @ts-ignore\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n const priceStruct = data.content.fields?.price_info?.price_feed?.price\n const priceValue = priceStruct?.price\n if (!priceValue) {\n console.warn(`unexpected pyth price struct, priceInfoObject: ${data.objectId}`)\n continue\n }\n const { magnitude, negative } = priceValue\n const conf = priceStruct.conf\n const timestamp = priceStruct.timestamp\n\n priceInfos.push({\n priceFeedId: pythInfo.priceFeedId,\n priceInfoObject: pythInfo.priceInfoObject,\n price: negative ? '-' + magnitude : magnitude,\n conf,\n publishTime: Number(timestamp),\n expiration: pythInfo.expiration\n })\n }\n return priceInfos\n}\n\nexport async function getPythStalePriceFeedIdV2(\n pythInfos: PythInfo[],\n options?: Partial<SuiClientOption>\n): Promise<string[]> {\n try {\n const returnData: string[] = []\n const latestPriceFeeds = await getOnChainPriceInfo(pythInfos, options)\n if (!latestPriceFeeds) return returnData\n\n const currentTimestamp = Math.floor(new Date().valueOf() / 1000)\n\n for (const priceFeed of latestPriceFeeds) {\n if (priceFeed.publishTime > currentTimestamp) {\n console.warn(\n `pyth price feed is invalid, id: ${priceFeed.priceFeedId}, publish time: ${priceFeed.publishTime}, current timestamp: ${currentTimestamp}`\n )\n continue\n }\n\n const maxTime = priceFeed.expiration || 60\n // 3s is the margin of error for the price feed.\n if (currentTimestamp - priceFeed.publishTime > maxTime) {\n console.info(\n `stale price feed, id: ${priceFeed.priceFeedId}, publish time: ${priceFeed.publishTime}, current timestamp: ${currentTimestamp}`\n )\n returnData.push(priceFeed.priceFeedId)\n }\n }\n return returnData\n } catch (error) {\n throw new Error(`failed to get pyth stale price feed id, msg: ${(error as Error).message}`)\n }\n}\n\n/**\n * Update Pyth price feeds in a transaction\n *\n * Fetches the latest price update data from Pyth Network and adds the update\n * operations to the transaction block.\n *\n * @param tx - The transaction block to add price feed updates to\n * @param priceFeedIds - Array of Pyth price feed IDs to update\n * @param options - Optional client and environment configuration\n * @returns Promise that resolves when price feeds are updated\n * @throws Error if failed to update price feeds\n */\nexport async function updatePythPriceFeeds(\n tx: Transaction,\n priceFeedIds: string[],\n options?: Partial<SuiClientOption & EnvOption & MarketOption>\n) {\n const client = options?.client ?? suiClient\n const config = await getConfig({\n ...options,\n cacheTime: DEFAULT_CACHE_TIME\n })\n try {\n const priceUpdateData = await getPythConnection(\n config.oracle.hermesEndpoint\n ).getPriceFeedsUpdateData(priceFeedIds)\n const suiPythClient = new SuiPythClient(\n client as any,\n config.oracle.pythStateId,\n config.oracle.wormholeStateId\n )\n\n return await suiPythClient.updatePriceFeeds(tx as any, priceUpdateData, priceFeedIds)\n } catch (error) {\n throw new Error(`failed to update pyth price feeds, msg: ${(error as Error).message}`)\n }\n}\n\n/**\n * Update oracle prices in the PTB (Programmable Transaction Block)\n *\n * This function updates price feeds for the lending protocol. It can optionally\n * update Pyth price feeds first if they are stale, then updates individual\n * price feeds in the oracle contract.\n *\n * @param tx - The transaction block to add price update operations to\n * @param priceFeeds - Array of oracle price feeds to update\n * @param options - Optional configuration including whether to update Pyth feeds\n * @returns The updated transaction block\n */\nexport async function updateOraclePricesPTB(\n tx: Transaction,\n priceFeeds: OraclePriceFeed[],\n options?: Partial<\n EnvOption &\n SuiClientOption &\n ServiceOption &\n MarketOption & {\n updatePythPriceFeeds?: boolean\n }\n >\n): Promise<Transaction> {\n const config = await getConfig({\n ...options,\n cacheTime: DEFAULT_CACHE_TIME\n })\n\n // Optionally update Pyth price feeds if they are stale\n if (options?.updatePythPriceFeeds) {\n const pythInfos = priceFeeds\n .filter((feed) => !!feed.pythPriceFeedId && !!feed.pythPriceInfoObject)\n .map((feed) => ({\n priceFeedId: feed.pythPriceFeedId,\n priceInfoObject: feed.pythPriceInfoObject,\n expiration: 30\n }))\n\n // Do not silently swallow Pyth stale-price update failures: the previous\n // catch kept building the tx with possibly stale on-chain prices and masked\n // real endpoint/RPC errors. Throw so callers are aware (avoids\n // lending/liquidation based on stale prices).\n const stalePriceFeedIds = await getPythStalePriceFeedIdV2(pythInfos, options)\n if (stalePriceFeedIds.length > 0) {\n await updatePythPriceFeeds(tx, stalePriceFeedIds, options)\n }\n }\n\n // Update individual price feeds in the oracle contract\n for (const priceFeed of priceFeeds) {\n tx.moveCall({\n target: `${config.oracle.packageId}::oracle_pro::${config.oracle.updateFunction ?? 'update_single_price_v2'}`,\n arguments: [\n tx.object('0x6'), // Clock object\n tx.object(config.oracle.oracleConfig), // Oracle configuration\n tx.object(config.oracle.priceOracle), // Price oracle contract\n tx.object(config.oracle.supraOracleHolder), // Supra oracle holder\n tx.object(priceFeed.pythPriceInfoObject), // Pyth price info object\n tx.object(config.oracle.switchboardAggregator),\n tx.pure.address(priceFeed.feedId) // Price feed ID\n ]\n })\n }\n return tx\n}\n\n/**\n * Get all available price feeds from the configuration\n *\n * @param options - Optional environment configuration\n * @returns Array of oracle price feed configurations\n */\nexport async function getPriceFeeds(\n options?: Partial<EnvOption & ServiceOption>\n): Promise<OraclePriceFeed[]> {\n const config = await getConfig({\n ...options,\n cacheTime: DEFAULT_CACHE_TIME\n })\n return config.oracle.feeds\n}\n\n/**\n * Filter price feeds based on lending state and pools\n *\n * This function filters price feeds to only include those that are relevant\n * to the current lending state or available pools.\n *\n * @param feeds - Array of price feeds to filter\n * @param filters - Filter criteria including lending state and pools\n * @returns Filtered array of price feeds\n */\nexport function filterPriceFeeds(\n feeds: OraclePriceFeed[],\n filters: {\n lendingState?: UserLendingInfo[]\n pools?: Pool[]\n lendingPositions?: LendingPosition[]\n }\n): OraclePriceFeed[] {\n return feeds.filter((feed) => {\n // Filter by lending state (user's current positions)\n if (filters?.lendingState) {\n const inState = filters.lendingState.find((state) => {\n return feed.oracleId === state.pool.oracleId\n })\n if (inState) {\n return true\n }\n }\n\n if (filters?.lendingPositions) {\n const inPosition = filters.lendingPositions.find((position) => {\n const availableTypes = [\n 'navi-lending-supply',\n 'navi-lending-borrow',\n 'navi-lending-emode-supply',\n 'navi-lending-emode-borrow'\n ]\n if (!availableTypes.includes(position.type)) {\n return false\n }\n const pool = position[position.type]?.pool\n return feed.oracleId === pool?.oracleId\n })\n if (inPosition) {\n return true\n }\n }\n\n // Filter by available pools\n if (filters?.pools) {\n const inPool = filters.pools.find((pool) => {\n return feed.oracleId === pool.oracleId\n })\n if (inPool) {\n return true\n }\n }\n return false\n })\n}\n\nexport async function updateOraclePriceBeforeUserOperationPTB(\n tx: Transaction,\n address: string,\n pools: Pool[],\n options?: Partial<\n EnvOption &\n SuiClientOption &\n MarketOption & {\n throws?: boolean\n }\n >\n) {\n let relevantFeeds: OraclePriceFeed[] | undefined\n try {\n const allPriceFeeds = await getPriceFeeds({\n ...options\n })\n\n const markets = [] as string[]\n\n pools.forEach((pool) => {\n if (!markets.includes(pool.market)) {\n markets.push(pool.market)\n }\n })\n\n const lendingPositions = await getLendingPositions(address, {\n ...options,\n markets\n })\n\n relevantFeeds = filterPriceFeeds(allPriceFeeds, {\n lendingPositions,\n pools\n })\n\n const updatedTx = await updateOraclePricesPTB(tx, relevantFeeds, {\n updatePythPriceFeeds: true,\n ...options\n })\n return updatedTx\n } catch (e) {\n if (options?.throws) {\n throw e\n }\n console.error(e)\n // Degraded path: a Pyth refresh failure happens before any moveCall is\n // appended, so the tx is still clean. Retry the oracle update without the\n // Pyth feed refresh (matches the pre-v2 behavior where Pyth failures were\n // swallowed but update_single_price calls were still appended) instead of\n // dropping the oracle update entirely.\n if (relevantFeeds) {\n try {\n return await updateOraclePricesPTB(tx, relevantFeeds, {\n ...options,\n updatePythPriceFeeds: false\n })\n } catch (fallbackError) {\n console.error(fallbackError)\n }\n }\n return tx\n }\n}\n"],"names":["pythConnections","getPythConnection","endpoint","url","conn","SuiPriceServiceConnection","getPythStalePriceFeedId","priceIds","options","returnData","config","getConfig","DEFAULT_CACHE_TIME","latestPriceFeeds","currentTimestamp","priceFeed","uncheckedPrice","error","getOnChainPriceInfo","pythInfos","priceInfos","client","suiClient","priceInfoObjectIds","k","priceInfoObjects","multiGetSuiObjects","obj","data","pythInfo","v","priceStruct","priceValue","magnitude","negative","conf","timestamp","getPythStalePriceFeedIdV2","maxTime","updatePythPriceFeeds","tx","priceFeedIds","priceUpdateData","SuiPythClient","updateOraclePricesPTB","priceFeeds","feed","stalePriceFeedIds","getPriceFeeds","filterPriceFeeds","feeds","filters","state","position","pool","updateOraclePriceBeforeUserOperationPTB","address","pools","relevantFeeds","allPriceFeeds","markets","lendingPositions","getLendingPositions","e","fallbackError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"oracle.js","sources":["../src/oracle.ts"],"sourcesContent":["/**\n * Oracle Price Feed Management for Lending Protocol\n *\n * This module provides oracle price feed functionality for the lending protocol.\n * It integrates with Pyth Network for real-time price data and manages price updates\n * for various assets used in lending operations.\n */\n\nimport { getConfig, DEFAULT_CACHE_TIME } from './config'\nimport type {\n OraclePriceFeed,\n EnvOption,\n UserLendingInfo,\n Pool,\n SuiClientOption,\n MarketOption,\n LendingPosition,\n ServiceOption,\n TransactionObjectArgument\n} from './types'\nimport { SuiPriceServiceConnection, SuiPythClient } from './pyth'\nimport { Transaction } from '@mysten/sui/transactions'\nimport { multiGetSuiObjects, suiClient } from './utils'\nimport { getLendingPositions } from './account'\n\ntype PythInfo = {\n priceFeedId: string\n priceInfoObject: string\n expiration?: number\n}\n\nexport type PythPriceInfo = {\n priceFeedId: string\n priceInfoObject: string\n price: string\n conf: string\n publishTime: number\n expiration?: number\n}\n\n/**\n * Pyth Network connection for price feed data\n * Connects to the Hermes endpoint for real-time price updates\n */\nconst pythConnections = new Map<string, SuiPriceServiceConnection>()\nconst getPythConnection = (endpoint?: string) => {\n const url = endpoint ?? 'https://hermes.pyth.network'\n let conn = pythConnections.get(url)\n if (!conn) {\n conn = new SuiPriceServiceConnection(url, { timeout: 10000 })\n pythConnections.set(url, conn)\n }\n return conn\n}\n\n/**\n * Get stale price feed IDs from Pyth Network\n *\n * Identifies price feeds that have not been updated recently (more than 30 seconds old).\n * This helps ensure that only fresh price data is used for lending operations.\n *\n * @param priceIds - Array of Pyth price feed IDs to check\n * @returns Array of stale price feed IDs that need updating\n * @throws Error if failed to fetch price feed data\n */\nexport async function getPythStalePriceFeedId(\n priceIds: string[],\n options?: Partial<EnvOption & MarketOption>\n): Promise<string[]> {\n try {\n const returnData: string[] = []\n const config = await getConfig({ ...options, cacheTime: DEFAULT_CACHE_TIME })\n const latestPriceFeeds = await getPythConnection(\n config.oracle.hermesEndpoint\n ).getLatestPriceFeeds(priceIds)\n if (!latestPriceFeeds) return returnData\n\n const currentTimestamp = Math.floor(new Date().valueOf() / 1000)\n for (const priceFeed of latestPriceFeeds) {\n const uncheckedPrice = priceFeed.getPriceUnchecked()\n if (uncheckedPrice.publishTime > currentTimestamp) {\n console.warn(\n `pyth price feed is invalid, id: ${priceFeed.id}, publish time: ${uncheckedPrice.publishTime}, current timestamp: ${currentTimestamp}`\n )\n continue\n }\n\n // From pyth state is 60, but setting it to 30 makes more sense.\n if (currentTimestamp - priceFeed.getPriceUnchecked().publishTime > 30) {\n console.info(\n `stale price feed, id: ${priceFeed.id}, publish time: ${uncheckedPrice.publishTime}, current timestamp: ${currentTimestamp}`\n )\n returnData.push(priceFeed.id)\n }\n }\n return returnData\n } catch (error) {\n throw new Error(`failed to get pyth stale price feed id, msg: ${(error as Error).message}`)\n }\n}\n\nasync function getOnChainPriceInfo(\n pythInfos: PythInfo[],\n options?: Partial<SuiClientOption>\n): Promise<PythPriceInfo[]> {\n // Whole-read failures (endpoint/RPC errors) propagate to the caller:\n // swallowing them here would silently skip the Pyth staleness update and let\n // transactions build against stale on-chain prices. Only per-feed anomalies\n // are skipped below.\n const priceInfos: PythPriceInfo[] = []\n const client = options?.client ?? suiClient\n\n const priceInfoObjectIds = pythInfos.map((k) => k.priceInfoObject)\n const priceInfoObjects = await multiGetSuiObjects(client, {\n ids: Array.from(new Set(priceInfoObjectIds)),\n options: { showContent: true }\n })\n for (const obj of priceInfoObjects) {\n const data = obj.data\n if (!data || !data.content || data.content.dataType !== 'moveObject') {\n console.warn(`fetched object ${data?.objectId} datatype should be moveObject`)\n continue\n }\n\n const pythInfo = pythInfos.find((v) => v.priceInfoObject == data.objectId)\n if (!pythInfo) {\n console.warn(`unable to find pyth info from array, priceInfoObject: ${data.objectId}`)\n continue\n }\n\n // The Sui v2 client returns nested Move structs directly, without the\n // per-level `.fields` wrapper the legacy JSON-RPC object shape carried.\n // Read the flattened shape and skip (not throw) on an unexpected object so\n // a single malformed feed can't abort the whole batch and silently leave\n // every on-chain price un-refreshed.\n // @ts-ignore\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n const priceStruct = data.content.fields?.price_info?.price_feed?.price\n const priceValue = priceStruct?.price\n if (!priceValue) {\n console.warn(`unexpected pyth price struct, priceInfoObject: ${data.objectId}`)\n continue\n }\n const { magnitude, negative } = priceValue\n const conf = priceStruct.conf\n const timestamp = priceStruct.timestamp\n\n priceInfos.push({\n priceFeedId: pythInfo.priceFeedId,\n priceInfoObject: pythInfo.priceInfoObject,\n price: negative ? '-' + magnitude : magnitude,\n conf,\n publishTime: Number(timestamp),\n expiration: pythInfo.expiration\n })\n }\n return priceInfos\n}\n\nexport async function getPythStalePriceFeedIdV2(\n pythInfos: PythInfo[],\n options?: Partial<SuiClientOption>\n): Promise<string[]> {\n try {\n const returnData: string[] = []\n const latestPriceFeeds = await getOnChainPriceInfo(pythInfos, options)\n if (!latestPriceFeeds) return returnData\n\n const currentTimestamp = Math.floor(new Date().valueOf() / 1000)\n\n for (const priceFeed of latestPriceFeeds) {\n if (priceFeed.publishTime > currentTimestamp) {\n console.warn(\n `pyth price feed is invalid, id: ${priceFeed.priceFeedId}, publish time: ${priceFeed.publishTime}, current timestamp: ${currentTimestamp}`\n )\n continue\n }\n\n const maxTime = priceFeed.expiration || 60\n // 3s is the margin of error for the price feed.\n if (currentTimestamp - priceFeed.publishTime > maxTime) {\n console.info(\n `stale price feed, id: ${priceFeed.priceFeedId}, publish time: ${priceFeed.publishTime}, current timestamp: ${currentTimestamp}`\n )\n returnData.push(priceFeed.priceFeedId)\n }\n }\n return returnData\n } catch (error) {\n throw new Error(`failed to get pyth stale price feed id, msg: ${(error as Error).message}`)\n }\n}\n\n/**\n * Update Pyth price feeds in a transaction\n *\n * Fetches the latest price update data from Pyth Network and adds the update\n * operations to the transaction block.\n *\n * @param tx - The transaction block to add price feed updates to\n * @param priceFeedIds - Array of Pyth price feed IDs to update\n * @param options - Optional client and environment configuration\n * @returns Promise that resolves when price feeds are updated\n * @throws Error if failed to update price feeds\n */\nexport async function updatePythPriceFeeds(\n tx: Transaction,\n priceFeedIds: string[],\n options?: Partial<\n SuiClientOption &\n EnvOption &\n MarketOption & {\n pythFeeCoin?: TransactionObjectArgument\n }\n >\n) {\n const client = options?.client ?? suiClient\n const config = await getConfig({\n ...options,\n cacheTime: DEFAULT_CACHE_TIME\n })\n try {\n const priceUpdateData = await getPythConnection(\n config.oracle.hermesEndpoint\n ).getPriceFeedsUpdateData(priceFeedIds)\n const suiPythClient = new SuiPythClient(\n client as any,\n config.oracle.pythStateId,\n config.oracle.wormholeStateId\n )\n\n return await suiPythClient.updatePriceFeeds(tx as any, priceUpdateData, priceFeedIds, {\n feeCoin: options?.pythFeeCoin\n })\n } catch (error) {\n throw new Error(`failed to update pyth price feeds, msg: ${(error as Error).message}`)\n }\n}\n\n/**\n * Update oracle prices in the PTB (Programmable Transaction Block)\n *\n * This function updates price feeds for the lending protocol. It can optionally\n * update Pyth price feeds first if they are stale, then updates individual\n * price feeds in the oracle contract.\n *\n * @param tx - The transaction block to add price update operations to\n * @param priceFeeds - Array of oracle price feeds to update\n * @param options - Optional configuration including whether to update Pyth feeds\n * @returns The updated transaction block\n */\nexport async function updateOraclePricesPTB(\n tx: Transaction,\n priceFeeds: OraclePriceFeed[],\n options?: Partial<\n EnvOption &\n SuiClientOption &\n ServiceOption &\n MarketOption & {\n updatePythPriceFeeds?: boolean\n /** Optional user-owned SUI coin used for Pyth update fees. Defaults to `tx.gas`. */\n pythFeeCoin?: TransactionObjectArgument\n }\n >\n): Promise<Transaction> {\n const config = await getConfig({\n ...options,\n cacheTime: DEFAULT_CACHE_TIME\n })\n\n // Optionally update Pyth price feeds if they are stale\n if (options?.updatePythPriceFeeds) {\n const pythInfos = priceFeeds\n .filter((feed) => !!feed.pythPriceFeedId && !!feed.pythPriceInfoObject)\n .map((feed) => ({\n priceFeedId: feed.pythPriceFeedId,\n priceInfoObject: feed.pythPriceInfoObject,\n expiration: 30\n }))\n\n // Do not silently swallow Pyth stale-price update failures: the previous\n // catch kept building the tx with possibly stale on-chain prices and masked\n // real endpoint/RPC errors. Throw so callers are aware (avoids\n // lending/liquidation based on stale prices).\n const stalePriceFeedIds = await getPythStalePriceFeedIdV2(pythInfos, options)\n if (stalePriceFeedIds.length > 0) {\n await updatePythPriceFeeds(tx, stalePriceFeedIds, options)\n }\n }\n\n // Update individual price feeds in the oracle contract\n for (const priceFeed of priceFeeds) {\n tx.moveCall({\n target: `${config.oracle.packageId}::oracle_pro::${config.oracle.updateFunction ?? 'update_single_price_v2'}`,\n arguments: [\n tx.object('0x6'), // Clock object\n tx.object(config.oracle.oracleConfig), // Oracle configuration\n tx.object(config.oracle.priceOracle), // Price oracle contract\n tx.object(config.oracle.supraOracleHolder), // Supra oracle holder\n tx.object(priceFeed.pythPriceInfoObject), // Pyth price info object\n tx.object(config.oracle.switchboardAggregator),\n tx.pure.address(priceFeed.feedId) // Price feed ID\n ]\n })\n }\n return tx\n}\n\n/**\n * Get all available price feeds from the configuration\n *\n * @param options - Optional environment configuration\n * @returns Array of oracle price feed configurations\n */\nexport async function getPriceFeeds(\n options?: Partial<EnvOption & ServiceOption>\n): Promise<OraclePriceFeed[]> {\n const config = await getConfig({\n ...options,\n cacheTime: DEFAULT_CACHE_TIME\n })\n return config.oracle.feeds\n}\n\n/**\n * Filter price feeds based on lending state and pools\n *\n * This function filters price feeds to only include those that are relevant\n * to the current lending state or available pools.\n *\n * @param feeds - Array of price feeds to filter\n * @param filters - Filter criteria including lending state and pools\n * @returns Filtered array of price feeds\n */\nexport function filterPriceFeeds(\n feeds: OraclePriceFeed[],\n filters: {\n lendingState?: UserLendingInfo[]\n pools?: Pool[]\n lendingPositions?: LendingPosition[]\n }\n): OraclePriceFeed[] {\n return feeds.filter((feed) => {\n // Filter by lending state (user's current positions)\n if (filters?.lendingState) {\n const inState = filters.lendingState.find((state) => {\n return feed.oracleId === state.pool.oracleId\n })\n if (inState) {\n return true\n }\n }\n\n if (filters?.lendingPositions) {\n const inPosition = filters.lendingPositions.find((position) => {\n const availableTypes = [\n 'navi-lending-supply',\n 'navi-lending-borrow',\n 'navi-lending-emode-supply',\n 'navi-lending-emode-borrow'\n ]\n if (!availableTypes.includes(position.type)) {\n return false\n }\n const pool = position[position.type]?.pool\n return feed.oracleId === pool?.oracleId\n })\n if (inPosition) {\n return true\n }\n }\n\n // Filter by available pools\n if (filters?.pools) {\n const inPool = filters.pools.find((pool) => {\n return feed.oracleId === pool.oracleId\n })\n if (inPool) {\n return true\n }\n }\n return false\n })\n}\n\nexport async function updateOraclePriceBeforeUserOperationPTB(\n tx: Transaction,\n address: string,\n pools: Pool[],\n options?: Partial<\n EnvOption &\n SuiClientOption &\n MarketOption & {\n throws?: boolean\n pythFeeCoin?: TransactionObjectArgument\n }\n >\n) {\n let relevantFeeds: OraclePriceFeed[] | undefined\n try {\n const allPriceFeeds = await getPriceFeeds({\n ...options\n })\n\n const markets = [] as string[]\n\n pools.forEach((pool) => {\n if (!markets.includes(pool.market)) {\n markets.push(pool.market)\n }\n })\n\n const lendingPositions = await getLendingPositions(address, {\n ...options,\n markets\n })\n\n relevantFeeds = filterPriceFeeds(allPriceFeeds, {\n lendingPositions,\n pools\n })\n\n const updatedTx = await updateOraclePricesPTB(tx, relevantFeeds, {\n updatePythPriceFeeds: true,\n ...options\n })\n return updatedTx\n } catch (e) {\n if (options?.throws) {\n throw e\n }\n console.error(e)\n // Degraded path: a Pyth refresh failure happens before any moveCall is\n // appended, so the tx is still clean. Retry the oracle update without the\n // Pyth feed refresh (matches the pre-v2 behavior where Pyth failures were\n // swallowed but update_single_price calls were still appended) instead of\n // dropping the oracle update entirely.\n if (relevantFeeds) {\n try {\n return await updateOraclePricesPTB(tx, relevantFeeds, {\n ...options,\n updatePythPriceFeeds: false\n })\n } catch (fallbackError) {\n console.error(fallbackError)\n }\n }\n return tx\n }\n}\n"],"names":["pythConnections","getPythConnection","endpoint","url","conn","SuiPriceServiceConnection","getPythStalePriceFeedId","priceIds","options","returnData","config","getConfig","DEFAULT_CACHE_TIME","latestPriceFeeds","currentTimestamp","priceFeed","uncheckedPrice","error","getOnChainPriceInfo","pythInfos","priceInfos","client","suiClient","priceInfoObjectIds","k","priceInfoObjects","multiGetSuiObjects","obj","data","pythInfo","v","priceStruct","priceValue","magnitude","negative","conf","timestamp","getPythStalePriceFeedIdV2","maxTime","updatePythPriceFeeds","tx","priceFeedIds","priceUpdateData","SuiPythClient","updateOraclePricesPTB","priceFeeds","feed","stalePriceFeedIds","getPriceFeeds","filterPriceFeeds","feeds","filters","state","position","pool","updateOraclePriceBeforeUserOperationPTB","address","pools","relevantFeeds","allPriceFeeds","markets","lendingPositions","getLendingPositions","e","fallbackError"],"mappings":"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"}
|
package/dist/package.json.js
CHANGED
package/dist/pyth.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NaviSuiClient } from './sui.js';
|
|
2
|
-
import { Transaction } from '@mysten/sui/transactions';
|
|
2
|
+
import { TransactionObjectArgument, Transaction } from '@mysten/sui/transactions';
|
|
3
3
|
|
|
4
4
|
type PriceFeed = {
|
|
5
5
|
id: string;
|
|
@@ -36,7 +36,9 @@ export declare class SuiPythClient {
|
|
|
36
36
|
private getCoreProvider;
|
|
37
37
|
private getMoveObjectJson;
|
|
38
38
|
private getDynamicMoveObjectJson;
|
|
39
|
-
updatePriceFeeds(tx: Transaction, updates: Uint8Array[], feedIds: string[]
|
|
39
|
+
updatePriceFeeds(tx: Transaction, updates: Uint8Array[], feedIds: string[], options?: {
|
|
40
|
+
feeCoin?: TransactionObjectArgument;
|
|
41
|
+
}): Promise<string[]>;
|
|
40
42
|
private getBaseUpdateFee;
|
|
41
43
|
private getPackageId;
|
|
42
44
|
private verifyVaas;
|
package/dist/pyth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pyth.d.ts","sourceRoot":"","sources":["../src/pyth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAuBtD,KAAK,SAAS,GAAG;IACf,EAAE,EAAE,MAAM,CAAA;IACV,iBAAiB,IAAI;QACnB,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF,CAAA;AAOD,KAAK,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,uBAAuB,CAAC,CAAC,GAAG;IAC3F,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAmHD,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;gBAEpB,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAKtD,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC;IAazE,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YAuB1D,GAAG;CA6BlB;AAED,qBAAa,aAAa;IAWtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAZlC,OAAO,CAAC,aAAa,CAAC,CAAQ;IAC9B,OAAO,CAAC,iBAAiB,CAAC,CAAQ;IAClC,OAAO,CAAC,cAAc,CAAC,CAGtB;IACD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAwC;IAC/E,OAAO,CAAC,aAAa,CAAC,CAAQ;gBAGX,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM;IAG1C,OAAO,CAAC,eAAe;YAaT,iBAAiB;YAkCjB,wBAAwB;IA6ChC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"pyth.d.ts","sourceRoot":"","sources":["../src/pyth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAuBtD,KAAK,SAAS,GAAG;IACf,EAAE,EAAE,MAAM,CAAA;IACV,iBAAiB,IAAI;QACnB,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF,CAAA;AAOD,KAAK,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,uBAAuB,CAAC,CAAC,GAAG;IAC3F,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAmHD,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;gBAEpB,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAKtD,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC;IAazE,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YAuB1D,GAAG;CA6BlB;AAED,qBAAa,aAAa;IAWtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAZlC,OAAO,CAAC,aAAa,CAAC,CAAQ;IAC9B,OAAO,CAAC,iBAAiB,CAAC,CAAQ;IAClC,OAAO,CAAC,cAAc,CAAC,CAGtB;IACD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAwC;IAC/E,OAAO,CAAC,aAAa,CAAC,CAAQ;gBAGX,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM;IAG1C,OAAO,CAAC,eAAe;YAaT,iBAAiB;YAkCjB,wBAAwB;IA6ChC,gBAAgB,CACpB,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,yBAAyB,CAAA;KAAE;YAYrC,gBAAgB;YAWhB,YAAY;YAmBZ,UAAU;YAeV,yBAAyB;YAwBzB,uBAAuB;YAiCvB,oBAAoB;YAOpB,gBAAgB;YAOhB,oBAAoB;YAyCpB,iBAAiB;IAoB/B,OAAO,CAAC,qCAAqC;CAO9C"}
|
package/dist/pyth.js
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
1
|
import { bcs as d } from "@mysten/sui/bcs";
|
|
2
2
|
import { SUI_CLOCK_OBJECT_ID as p } from "@mysten/sui/utils";
|
|
3
3
|
const b = 16 * 1024;
|
|
4
|
-
function u(
|
|
5
|
-
return
|
|
4
|
+
function u(o) {
|
|
5
|
+
return o.replace(/^0x/i, "");
|
|
6
6
|
}
|
|
7
|
-
function h(
|
|
8
|
-
const e = u(
|
|
7
|
+
function h(o) {
|
|
8
|
+
const e = u(o), t = new Uint8Array(e.length / 2);
|
|
9
9
|
for (let r = 0; r < t.length; r += 1)
|
|
10
10
|
t[r] = parseInt(e.slice(r * 2, r * 2 + 2), 16);
|
|
11
11
|
return t;
|
|
12
12
|
}
|
|
13
|
-
function g(
|
|
14
|
-
return (
|
|
13
|
+
function g(o, e) {
|
|
14
|
+
return (o[e] << 8) + o[e + 1];
|
|
15
15
|
}
|
|
16
|
-
function f(
|
|
17
|
-
return d.vector(d.U8).serialize(Array.from(
|
|
16
|
+
function f(o) {
|
|
17
|
+
return d.vector(d.U8).serialize(Array.from(o), {
|
|
18
18
|
maxSize: b
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
-
function y(
|
|
21
|
+
function y(o, e) {
|
|
22
22
|
return {
|
|
23
|
-
type:
|
|
23
|
+
type: o,
|
|
24
24
|
bcs: e
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
-
function m(
|
|
28
|
-
return d.vector(d.U8).serialize(Array.from(new TextEncoder().encode(
|
|
27
|
+
function m(o) {
|
|
28
|
+
return d.vector(d.U8).serialize(Array.from(new TextEncoder().encode(o))).toBytes();
|
|
29
29
|
}
|
|
30
|
-
function I(
|
|
30
|
+
function I(o) {
|
|
31
31
|
return d.struct("PriceIdentifier", {
|
|
32
32
|
bytes: d.vector(d.U8)
|
|
33
33
|
}).serialize({
|
|
34
|
-
bytes: Array.from(
|
|
34
|
+
bytes: Array.from(o)
|
|
35
35
|
}).toBytes();
|
|
36
36
|
}
|
|
37
|
-
function j(
|
|
37
|
+
function j(o) {
|
|
38
38
|
const e = [];
|
|
39
39
|
let t = 0, r = 0;
|
|
40
|
-
for (let i = 0; i <
|
|
41
|
-
const
|
|
42
|
-
|
|
40
|
+
for (let i = 0; i < o.length; i += 1) {
|
|
41
|
+
const a = o[i];
|
|
42
|
+
a === "<" ? t += 1 : a === ">" ? t -= 1 : a === "," && t === 0 && (e.push(o.slice(r, i).trim()), r = i + 1);
|
|
43
43
|
}
|
|
44
|
-
return e.push(
|
|
44
|
+
return e.push(o.slice(r).trim()), e;
|
|
45
45
|
}
|
|
46
|
-
function w(
|
|
47
|
-
const t =
|
|
46
|
+
function w(o) {
|
|
47
|
+
const t = o.indexOf("::table::Table"), r = o.indexOf("<", t), i = o.lastIndexOf(">"), a = "::price_identifier::PriceIdentifier";
|
|
48
48
|
if (t < 0 || r < 0 || i <= r)
|
|
49
|
-
throw new Error(`Unexpected Pyth price table type: ${
|
|
50
|
-
const [c, n] = j(
|
|
51
|
-
if (!c?.endsWith(
|
|
52
|
-
throw new Error(`Unexpected Pyth price table type arguments: ${
|
|
53
|
-
return c.slice(0, -
|
|
49
|
+
throw new Error(`Unexpected Pyth price table type: ${o}`);
|
|
50
|
+
const [c, n] = j(o.slice(r + 1, i));
|
|
51
|
+
if (!c?.endsWith(a) || !n?.endsWith("::object::ID"))
|
|
52
|
+
throw new Error(`Unexpected Pyth price table type arguments: ${o}`);
|
|
53
|
+
return c.slice(0, -a.length);
|
|
54
54
|
}
|
|
55
|
-
function v(
|
|
56
|
-
return Uint8Array.from(atob(
|
|
55
|
+
function v(o) {
|
|
56
|
+
return Uint8Array.from(atob(o), (e) => e.charCodeAt(0));
|
|
57
57
|
}
|
|
58
58
|
class F {
|
|
59
59
|
constructor(e, t) {
|
|
@@ -86,7 +86,7 @@ class F {
|
|
|
86
86
|
return i.map(v);
|
|
87
87
|
}
|
|
88
88
|
async get(e, t, r) {
|
|
89
|
-
const i = new AbortController(),
|
|
89
|
+
const i = new AbortController(), a = setTimeout(() => i.abort(), this.timeout), c = new URL(`${this.endpoint}${e}`);
|
|
90
90
|
for (const [n, s] of Object.entries(r ?? {}))
|
|
91
91
|
c.searchParams.set(n, s);
|
|
92
92
|
for (const n of t)
|
|
@@ -99,7 +99,7 @@ class F {
|
|
|
99
99
|
throw new Error(`Hermes request failed: ${n.status} ${n.statusText}`);
|
|
100
100
|
return await n.json();
|
|
101
101
|
} finally {
|
|
102
|
-
clearTimeout(
|
|
102
|
+
clearTimeout(a);
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
}
|
|
@@ -139,15 +139,15 @@ class _ {
|
|
|
139
139
|
async getDynamicMoveObjectJson(e, t) {
|
|
140
140
|
const r = this.getCoreProvider();
|
|
141
141
|
if (r) {
|
|
142
|
-
const
|
|
142
|
+
const a = await r.getDynamicObjectField({
|
|
143
143
|
parentId: e,
|
|
144
144
|
name: t,
|
|
145
145
|
include: { json: !0 }
|
|
146
146
|
});
|
|
147
|
-
return
|
|
148
|
-
objectId:
|
|
149
|
-
type:
|
|
150
|
-
fields:
|
|
147
|
+
return a.object ? {
|
|
148
|
+
objectId: a.object.objectId,
|
|
149
|
+
type: a.object.type,
|
|
150
|
+
fields: a.object.json
|
|
151
151
|
} : null;
|
|
152
152
|
}
|
|
153
153
|
if (!this.provider.getDynamicFieldObject)
|
|
@@ -166,12 +166,12 @@ class _ {
|
|
|
166
166
|
fields: void 0
|
|
167
167
|
} : null;
|
|
168
168
|
}
|
|
169
|
-
async updatePriceFeeds(e, t, r) {
|
|
170
|
-
const
|
|
171
|
-
e.gas,
|
|
172
|
-
r.map(() => e.pure.u64(
|
|
169
|
+
async updatePriceFeeds(e, t, r, i) {
|
|
170
|
+
const a = await this.getPythPackageId(), c = await this.verifyVaasAndGetHotPotato(e, t, a), n = await this.getBaseUpdateFee(), s = e.splitCoins(
|
|
171
|
+
i?.feeCoin ?? e.gas,
|
|
172
|
+
r.map(() => e.pure.u64(n))
|
|
173
173
|
);
|
|
174
|
-
return this.executePriceFeedUpdates(e,
|
|
174
|
+
return this.executePriceFeedUpdates(e, a, r, c, s);
|
|
175
175
|
}
|
|
176
176
|
async getBaseUpdateFee() {
|
|
177
177
|
if (this.baseUpdateFee === void 0) {
|
|
@@ -187,9 +187,9 @@ class _ {
|
|
|
187
187
|
if (t?.fields) {
|
|
188
188
|
const r = t.fields;
|
|
189
189
|
if ("upgrade_cap" in r) {
|
|
190
|
-
const i = r.upgrade_cap,
|
|
191
|
-
if (
|
|
192
|
-
return
|
|
190
|
+
const i = r.upgrade_cap, a = i?.package ?? i?.fields?.package;
|
|
191
|
+
if (a)
|
|
192
|
+
return a;
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
throw new Error(`Cannot fetch package id for object ${e}`);
|
|
@@ -197,7 +197,7 @@ class _ {
|
|
|
197
197
|
async verifyVaas(e, t) {
|
|
198
198
|
const r = await this.getWormholePackageId();
|
|
199
199
|
return e.map((i) => {
|
|
200
|
-
const [
|
|
200
|
+
const [a] = t.moveCall({
|
|
201
201
|
target: `${r}::vaa::parse_and_verify`,
|
|
202
202
|
arguments: [
|
|
203
203
|
t.object(this.wormholeStateId),
|
|
@@ -205,7 +205,7 @@ class _ {
|
|
|
205
205
|
t.object(p)
|
|
206
206
|
]
|
|
207
207
|
});
|
|
208
|
-
return
|
|
208
|
+
return a;
|
|
209
209
|
});
|
|
210
210
|
}
|
|
211
211
|
async verifyVaasAndGetHotPotato(e, t, r) {
|
|
@@ -213,18 +213,18 @@ class _ {
|
|
|
213
213
|
throw new Error(
|
|
214
214
|
"SDK does not support sending multiple accumulator messages in a single transaction"
|
|
215
215
|
);
|
|
216
|
-
const i = this.extractVaaBytesFromAccumulatorMessage(t[0]), [
|
|
216
|
+
const i = this.extractVaaBytesFromAccumulatorMessage(t[0]), [a] = await this.verifyVaas([i], e), [c] = e.moveCall({
|
|
217
217
|
target: `${r}::pyth::create_authenticated_price_infos_using_accumulator`,
|
|
218
218
|
arguments: [
|
|
219
219
|
e.object(this.pythStateId),
|
|
220
220
|
e.pure(f(t[0])),
|
|
221
|
-
|
|
221
|
+
a,
|
|
222
222
|
e.object(p)
|
|
223
223
|
]
|
|
224
224
|
});
|
|
225
225
|
return c;
|
|
226
226
|
}
|
|
227
|
-
async executePriceFeedUpdates(e, t, r, i,
|
|
227
|
+
async executePriceFeedUpdates(e, t, r, i, a) {
|
|
228
228
|
const c = [];
|
|
229
229
|
for (const [n, s] of r.entries()) {
|
|
230
230
|
const l = await this.getPriceFeedObjectId(s);
|
|
@@ -236,7 +236,7 @@ class _ {
|
|
|
236
236
|
e.object(this.pythStateId),
|
|
237
237
|
i,
|
|
238
238
|
e.object(l),
|
|
239
|
-
|
|
239
|
+
a[n],
|
|
240
240
|
e.object(p)
|
|
241
241
|
]
|
|
242
242
|
});
|
|
@@ -256,11 +256,11 @@ class _ {
|
|
|
256
256
|
async getPriceFeedObjectId(e) {
|
|
257
257
|
const t = u(e);
|
|
258
258
|
if (!this.priceFeedObjectIdCache.has(t)) {
|
|
259
|
-
const { id: r, fieldType: i } = await this.getPriceTableInfo(),
|
|
259
|
+
const { id: r, fieldType: i } = await this.getPriceTableInfo(), a = `${i}::price_identifier::PriceIdentifier`, c = this.getCoreProvider();
|
|
260
260
|
if (c) {
|
|
261
261
|
const { dynamicField: n } = await c.getDynamicField({
|
|
262
262
|
parentId: r,
|
|
263
|
-
name: y(
|
|
263
|
+
name: y(a, I(h(t)))
|
|
264
264
|
}), s = n?.value?.bcs;
|
|
265
265
|
this.priceFeedObjectIdCache.set(
|
|
266
266
|
t,
|
|
@@ -268,7 +268,7 @@ class _ {
|
|
|
268
268
|
);
|
|
269
269
|
} else {
|
|
270
270
|
const n = await this.getDynamicMoveObjectJson(r, {
|
|
271
|
-
type:
|
|
271
|
+
type: a,
|
|
272
272
|
value: {
|
|
273
273
|
bytes: Array.from(h(t))
|
|
274
274
|
}
|
|
@@ -294,8 +294,8 @@ class _ {
|
|
|
294
294
|
return this.priceTableInfo;
|
|
295
295
|
}
|
|
296
296
|
extractVaaBytesFromAccumulatorMessage(e) {
|
|
297
|
-
const r = 7 + e[6] + 1, i = g(e, r),
|
|
298
|
-
return e.subarray(
|
|
297
|
+
const r = 7 + e[6] + 1, i = g(e, r), a = r + 2;
|
|
298
|
+
return e.subarray(a, a + i);
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
export {
|
package/dist/pyth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pyth.js","sources":["../src/pyth.ts"],"sourcesContent":["import type { NaviSuiClient } from './sui'\nimport { Transaction } from '@mysten/sui/transactions'\nimport { bcs } from '@mysten/sui/bcs'\nimport { SUI_CLOCK_OBJECT_ID } from '@mysten/sui/utils'\n\ntype HermesPrice = {\n price: string\n conf: string\n expo: number\n publish_time: number\n}\n\ntype HermesPriceFeedResponse = {\n id: string\n price: HermesPrice\n}\n\ntype HermesPriceUpdateResponse = {\n binary?: {\n encoding?: string\n data?: string[]\n }\n}\n\ntype PriceFeed = {\n id: string\n getPriceUnchecked(): {\n price: string\n conf: string\n expo: number\n publishTime: number\n }\n}\n\ntype CoreDynamicFieldName = {\n type: string\n bcs: Uint8Array\n}\n\ntype SuiPythProvider = Partial<Pick<NaviSuiClient, 'getObject' | 'getDynamicFieldObject'>> & {\n core?: unknown\n}\n\ntype SuiPythCoreProvider = {\n getObject(options: {\n objectId: string\n include?: { json?: boolean; content?: boolean }\n }): Promise<{\n object?: { objectId: string; type?: string; json?: Record<string, unknown> | null }\n }>\n getDynamicObjectField(options: {\n parentId: string\n name: CoreDynamicFieldName\n include?: { json?: boolean; content?: boolean }\n }): Promise<{\n object?: { objectId: string; type?: string; json?: Record<string, unknown> | null }\n }>\n getDynamicField(options: { parentId: string; name: CoreDynamicFieldName }): Promise<{\n dynamicField?: { value?: { type?: string; bcs?: Uint8Array } }\n }>\n}\n\nconst MAX_ARGUMENT_SIZE = 16 * 1024\n\nfunction normalizePriceId(priceId: string) {\n return priceId.replace(/^0x/i, '')\n}\n\nfunction hexToBytes(hex: string) {\n const normalized = normalizePriceId(hex)\n const bytes = new Uint8Array(normalized.length / 2)\n for (let i = 0; i < bytes.length; i += 1) {\n bytes[i] = parseInt(normalized.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\nfunction readUint16BE(bytes: Uint8Array, offset: number) {\n return (bytes[offset] << 8) + bytes[offset + 1]\n}\n\nfunction toPureBytes(bytes: Uint8Array) {\n return bcs.vector(bcs.U8).serialize(Array.from(bytes), {\n maxSize: MAX_ARGUMENT_SIZE\n })\n}\n\nfunction toDynamicFieldName(type: string, bytes: Uint8Array): CoreDynamicFieldName {\n return {\n type,\n bcs: bytes\n }\n}\n\nfunction encodeVectorU8(value: string) {\n return bcs\n .vector(bcs.U8)\n .serialize(Array.from(new TextEncoder().encode(value)))\n .toBytes()\n}\n\nfunction encodePriceIdentifier(bytes: Uint8Array) {\n return bcs\n .struct('PriceIdentifier', {\n bytes: bcs.vector(bcs.U8)\n })\n .serialize({\n bytes: Array.from(bytes)\n })\n .toBytes()\n}\n\nfunction splitTopLevelTypeArgs(args: string) {\n const parts: string[] = []\n let depth = 0\n let start = 0\n\n for (let index = 0; index < args.length; index += 1) {\n const char = args[index]\n if (char === '<') {\n depth += 1\n } else if (char === '>') {\n depth -= 1\n } else if (char === ',' && depth === 0) {\n parts.push(args.slice(start, index).trim())\n start = index + 1\n }\n }\n\n parts.push(args.slice(start).trim())\n return parts\n}\n\nfunction getPythPackageIdFromPriceTableType(type: string) {\n const tablePrefix = '::table::Table'\n const tableIndex = type.indexOf(tablePrefix)\n const argsStart = type.indexOf('<', tableIndex)\n const argsEnd = type.lastIndexOf('>')\n const priceIdentifierSuffix = '::price_identifier::PriceIdentifier'\n\n if (tableIndex < 0 || argsStart < 0 || argsEnd <= argsStart) {\n throw new Error(`Unexpected Pyth price table type: ${type}`)\n }\n\n const [keyType, valueType] = splitTopLevelTypeArgs(type.slice(argsStart + 1, argsEnd))\n if (!keyType?.endsWith(priceIdentifierSuffix) || !valueType?.endsWith('::object::ID')) {\n throw new Error(`Unexpected Pyth price table type arguments: ${type}`)\n }\n\n return keyType.slice(0, -priceIdentifierSuffix.length)\n}\n\nfunction base64ToBytes(value: string) {\n return Uint8Array.from(atob(value), (char) => char.charCodeAt(0))\n}\n\nexport class SuiPriceServiceConnection {\n private readonly endpoint: string\n private readonly timeout: number\n\n constructor(endpoint: string, options?: { timeout?: number }) {\n this.endpoint = endpoint.replace(/\\/$/, '')\n this.timeout = options?.timeout ?? 10000\n }\n\n async getLatestPriceFeeds(priceIds: string[]): Promise<PriceFeed[] | undefined> {\n const data = await this.get<HermesPriceFeedResponse[]>('/api/latest_price_feeds', priceIds)\n return data.map((feed) => ({\n id: feed.id,\n getPriceUnchecked: () => ({\n price: feed.price.price,\n conf: feed.price.conf,\n expo: feed.price.expo,\n publishTime: feed.price.publish_time\n })\n }))\n }\n\n async getPriceFeedsUpdateData(priceIds: string[]): Promise<Uint8Array[]> {\n const response = await this.get<HermesPriceUpdateResponse>(\n '/v2/updates/price/latest',\n priceIds,\n {\n encoding: 'base64',\n parsed: 'false'\n }\n )\n const encoding = response.binary?.encoding\n const data = response.binary?.data ?? []\n\n if (encoding && encoding !== 'base64') {\n throw new Error(`Unsupported Hermes price update encoding: ${encoding}`)\n }\n\n if (data.length === 0) {\n throw new Error('Hermes price update response did not include binary update data')\n }\n\n return data.map(base64ToBytes)\n }\n\n private async get<T>(\n pathname: string,\n priceIds: string[],\n searchParams?: Record<string, string>\n ): Promise<T> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), this.timeout)\n const url = new URL(`${this.endpoint}${pathname}`)\n\n for (const [key, value] of Object.entries(searchParams ?? {})) {\n url.searchParams.set(key, value)\n }\n\n for (const priceId of priceIds) {\n url.searchParams.append('ids[]', normalizePriceId(priceId))\n }\n\n try {\n const res = await fetch(url, {\n signal: controller.signal\n })\n if (!res.ok) {\n throw new Error(`Hermes request failed: ${res.status} ${res.statusText}`)\n }\n return (await res.json()) as T\n } finally {\n clearTimeout(timeout)\n }\n }\n}\n\nexport class SuiPythClient {\n private pythPackageId?: string\n private wormholePackageId?: string\n private priceTableInfo?: {\n id: string\n fieldType: string\n }\n private readonly priceFeedObjectIdCache = new Map<string, string | undefined>()\n private baseUpdateFee?: number\n\n constructor(\n private readonly provider: SuiPythProvider,\n private readonly pythStateId: string,\n private readonly wormholeStateId: string\n ) {}\n\n private getCoreProvider(): SuiPythCoreProvider | null {\n const core = this.provider.core as Partial<SuiPythCoreProvider> | undefined\n if (\n core &&\n typeof core.getObject === 'function' &&\n typeof core.getDynamicObjectField === 'function' &&\n typeof core.getDynamicField === 'function'\n ) {\n return core as SuiPythCoreProvider\n }\n return null\n }\n\n private async getMoveObjectJson(objectId: string) {\n const core = this.getCoreProvider()\n if (core) {\n const result = await core.getObject({\n objectId,\n include: { json: true }\n })\n if (!result.object) {\n return null\n }\n return {\n objectId: result.object.objectId,\n type: result.object.type,\n fields: result.object.json\n }\n }\n\n if (!this.provider.getObject) {\n throw new Error('Sui Pyth provider does not support getObject')\n }\n const result = await this.provider.getObject({\n id: objectId,\n options: { showContent: true }\n })\n if (!result.data || !result.data.content || result.data.content.dataType !== 'moveObject') {\n return null\n }\n return {\n objectId: result.data.objectId,\n type: result.data.type,\n fields: result.data.content.fields as Record<string, unknown>\n }\n }\n\n private async getDynamicMoveObjectJson(parentId: string, name: CoreDynamicFieldName | any) {\n const core = this.getCoreProvider()\n if (core) {\n const result = await core.getDynamicObjectField({\n parentId,\n name,\n include: { json: true }\n })\n if (!result.object) {\n return null\n }\n return {\n objectId: result.object.objectId,\n type: result.object.type,\n fields: result.object.json\n }\n }\n\n if (!this.provider.getDynamicFieldObject) {\n throw new Error('Sui Pyth provider does not support getDynamicFieldObject')\n }\n const result = await this.provider.getDynamicFieldObject({\n parentId,\n name\n })\n if (!result.data) {\n return null\n }\n if (!result.data.content) {\n return {\n objectId: result.data.objectId,\n type: result.data.type,\n fields: undefined\n }\n }\n if (result.data.content.dataType !== 'moveObject') {\n return null\n }\n return {\n objectId: result.data.objectId,\n type: result.data.type,\n fields: result.data.content.fields as Record<string, unknown>\n }\n }\n\n async updatePriceFeeds(tx: Transaction, updates: Uint8Array[], feedIds: string[]) {\n const packageId = await this.getPythPackageId()\n const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId)\n const baseUpdateFee = await this.getBaseUpdateFee()\n const coins = tx.splitCoins(\n tx.gas,\n feedIds.map(() => tx.pure.u64(baseUpdateFee))\n )\n return this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins)\n }\n\n private async getBaseUpdateFee() {\n if (this.baseUpdateFee === undefined) {\n const result = await this.getMoveObjectJson(this.pythStateId)\n if (!result?.fields) {\n throw new Error('Unable to fetch pyth state object')\n }\n this.baseUpdateFee = Number((result.fields as any).base_update_fee)\n }\n return this.baseUpdateFee\n }\n\n private async getPackageId(objectId: string) {\n const result = await this.getMoveObjectJson(objectId)\n if (result?.fields) {\n const fields = result.fields as any\n if ('upgrade_cap' in fields) {\n // Sui v2 Core (gRPC) returns flat json (upgrade_cap.package) while legacy\n // JSON-RPC nests it (upgrade_cap.fields.package). Support both; otherwise\n // the Core path cannot resolve the packageId and getPythPackageId /\n // getWormholePackageId throw, breaking Pyth price feed updates entirely.\n const upgradeCap = fields.upgrade_cap\n const packageId = upgradeCap?.package ?? upgradeCap?.fields?.package\n if (packageId) {\n return packageId as string\n }\n }\n }\n throw new Error(`Cannot fetch package id for object ${objectId}`)\n }\n\n private async verifyVaas(vaas: Uint8Array[], tx: Transaction) {\n const wormholePackageId = await this.getWormholePackageId()\n return vaas.map((vaa) => {\n const [verifiedVaa] = tx.moveCall({\n target: `${wormholePackageId}::vaa::parse_and_verify`,\n arguments: [\n tx.object(this.wormholeStateId),\n tx.pure(toPureBytes(vaa)),\n tx.object(SUI_CLOCK_OBJECT_ID)\n ]\n })\n return verifiedVaa\n })\n }\n\n private async verifyVaasAndGetHotPotato(\n tx: Transaction,\n updates: Uint8Array[],\n packageId: string\n ) {\n if (updates.length > 1) {\n throw new Error(\n 'SDK does not support sending multiple accumulator messages in a single transaction'\n )\n }\n const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0])\n const [verifiedVaa] = await this.verifyVaas([vaa], tx)\n const [priceUpdatesHotPotato] = tx.moveCall({\n target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,\n arguments: [\n tx.object(this.pythStateId),\n tx.pure(toPureBytes(updates[0])),\n verifiedVaa,\n tx.object(SUI_CLOCK_OBJECT_ID)\n ]\n })\n return priceUpdatesHotPotato\n }\n\n private async executePriceFeedUpdates(\n tx: Transaction,\n packageId: string,\n feedIds: string[],\n priceUpdatesHotPotato: any,\n coins: any[]\n ) {\n const priceInfoObjects: string[] = []\n for (const [coinId, feedId] of feedIds.entries()) {\n const priceInfoObjectId = await this.getPriceFeedObjectId(feedId)\n if (!priceInfoObjectId) {\n throw new Error(`Price feed ${feedId} not found, please create it first`)\n }\n priceInfoObjects.push(priceInfoObjectId)\n ;[priceUpdatesHotPotato] = tx.moveCall({\n target: `${packageId}::pyth::update_single_price_feed`,\n arguments: [\n tx.object(this.pythStateId),\n priceUpdatesHotPotato,\n tx.object(priceInfoObjectId),\n coins[coinId],\n tx.object(SUI_CLOCK_OBJECT_ID)\n ]\n })\n }\n tx.moveCall({\n target: `${packageId}::hot_potato_vector::destroy`,\n arguments: [priceUpdatesHotPotato],\n typeArguments: [`${packageId}::price_info::PriceInfo`]\n })\n return priceInfoObjects\n }\n\n private async getWormholePackageId() {\n if (!this.wormholePackageId) {\n this.wormholePackageId = await this.getPackageId(this.wormholeStateId)\n }\n return this.wormholePackageId\n }\n\n private async getPythPackageId() {\n if (!this.pythPackageId) {\n this.pythPackageId = await this.getPackageId(this.pythStateId)\n }\n return this.pythPackageId\n }\n\n private async getPriceFeedObjectId(feedId: string) {\n const normalizedFeedId = normalizePriceId(feedId)\n if (!this.priceFeedObjectIdCache.has(normalizedFeedId)) {\n const { id: tableId, fieldType } = await this.getPriceTableInfo()\n const nameType = `${fieldType}::price_identifier::PriceIdentifier`\n\n const core = this.getCoreProvider()\n if (core) {\n // Pyth's price table stores entries as plain dynamic fields\n // (0x2::dynamic_field::Field<PriceIdentifier, ID>). getDynamicObjectField\n // must not be used here: it derives the child id from\n // Wrapper<PriceIdentifier> and resolves to an object that does not exist\n // on chain, aborting every Pyth price feed update.\n const { dynamicField } = await core.getDynamicField({\n parentId: tableId,\n name: toDynamicFieldName(nameType, encodePriceIdentifier(hexToBytes(normalizedFeedId)))\n })\n const valueBcs = dynamicField?.value?.bcs\n this.priceFeedObjectIdCache.set(\n normalizedFeedId,\n valueBcs && valueBcs.length === 32\n ? bcs.Address.parse(Uint8Array.from(valueBcs))\n : undefined\n )\n } else {\n const result = await this.getDynamicMoveObjectJson(tableId, {\n type: nameType,\n value: {\n bytes: Array.from(hexToBytes(normalizedFeedId))\n }\n })\n if (!result?.fields) {\n this.priceFeedObjectIdCache.set(normalizedFeedId, undefined)\n } else {\n this.priceFeedObjectIdCache.set(normalizedFeedId, (result.fields as any).value)\n }\n }\n }\n return this.priceFeedObjectIdCache.get(normalizedFeedId)\n }\n\n private async getPriceTableInfo() {\n if (!this.priceTableInfo) {\n const fieldName = this.getCoreProvider()\n ? toDynamicFieldName('vector<u8>', encodeVectorU8('price_info'))\n : {\n type: 'vector<u8>',\n value: 'price_info'\n }\n const result = await this.getDynamicMoveObjectJson(this.pythStateId, fieldName)\n if (!result?.type) {\n throw new Error('Price Table not found, contract may not be initialized')\n }\n this.priceTableInfo = {\n id: result.objectId,\n fieldType: getPythPackageIdFromPriceTableType(result.type)\n }\n }\n return this.priceTableInfo\n }\n\n private extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Uint8Array) {\n const trailingPayloadSize = accumulatorMessage[6]\n const vaaSizeOffset = 7 + trailingPayloadSize + 1\n const vaaSize = readUint16BE(accumulatorMessage, vaaSizeOffset)\n const vaaOffset = vaaSizeOffset + 2\n return accumulatorMessage.subarray(vaaOffset, vaaOffset + vaaSize)\n }\n}\n"],"names":["MAX_ARGUMENT_SIZE","normalizePriceId","priceId","hexToBytes","hex","normalized","bytes","i","readUint16BE","offset","toPureBytes","bcs","toDynamicFieldName","type","encodeVectorU8","value","encodePriceIdentifier","splitTopLevelTypeArgs","args","parts","depth","start","index","char","getPythPackageIdFromPriceTableType","tableIndex","argsStart","argsEnd","priceIdentifierSuffix","keyType","valueType","base64ToBytes","SuiPriceServiceConnection","endpoint","options","priceIds","feed","response","encoding","data","pathname","searchParams","controller","timeout","url","key","res","SuiPythClient","provider","pythStateId","wormholeStateId","core","objectId","result","parentId","name","tx","updates","feedIds","packageId","priceUpdatesHotPotato","baseUpdateFee","coins","fields","upgradeCap","vaas","wormholePackageId","vaa","verifiedVaa","SUI_CLOCK_OBJECT_ID","priceInfoObjects","coinId","feedId","priceInfoObjectId","normalizedFeedId","tableId","fieldType","nameType","dynamicField","valueBcs","fieldName","accumulatorMessage","vaaSizeOffset","vaaSize","vaaOffset"],"mappings":";;AA8DA,MAAMA,IAAoB,KAAK;AAE/B,SAASC,EAAiBC,GAAiB;AACzC,SAAOA,EAAQ,QAAQ,QAAQ,EAAE;AACnC;AAEA,SAASC,EAAWC,GAAa;AAC/B,QAAMC,IAAaJ,EAAiBG,CAAG,GACjCE,IAAQ,IAAI,WAAWD,EAAW,SAAS,CAAC;AAClD,WAASE,IAAI,GAAGA,IAAID,EAAM,QAAQC,KAAK;AACrC,IAAAD,EAAMC,CAAC,IAAI,SAASF,EAAW,MAAME,IAAI,GAAGA,IAAI,IAAI,CAAC,GAAG,EAAE;AAE5D,SAAOD;AACT;AAEA,SAASE,EAAaF,GAAmBG,GAAgB;AACvD,UAAQH,EAAMG,CAAM,KAAK,KAAKH,EAAMG,IAAS,CAAC;AAChD;AAEA,SAASC,EAAYJ,GAAmB;AACtC,SAAOK,EAAI,OAAOA,EAAI,EAAE,EAAE,UAAU,MAAM,KAAKL,CAAK,GAAG;AAAA,IACrD,SAASN;AAAA,EAAA,CACV;AACH;AAEA,SAASY,EAAmBC,GAAcP,GAAyC;AACjF,SAAO;AAAA,IACL,MAAAO;AAAA,IACA,KAAKP;AAAA,EAAA;AAET;AAEA,SAASQ,EAAeC,GAAe;AACrC,SAAOJ,EACJ,OAAOA,EAAI,EAAE,EACb,UAAU,MAAM,KAAK,IAAI,YAAA,EAAc,OAAOI,CAAK,CAAC,CAAC,EACrD,QAAA;AACL;AAEA,SAASC,EAAsBV,GAAmB;AAChD,SAAOK,EACJ,OAAO,mBAAmB;AAAA,IACzB,OAAOA,EAAI,OAAOA,EAAI,EAAE;AAAA,EAAA,CACzB,EACA,UAAU;AAAA,IACT,OAAO,MAAM,KAAKL,CAAK;AAAA,EAAA,CACxB,EACA,QAAA;AACL;AAEA,SAASW,EAAsBC,GAAc;AAC3C,QAAMC,IAAkB,CAAA;AACxB,MAAIC,IAAQ,GACRC,IAAQ;AAEZ,WAASC,IAAQ,GAAGA,IAAQJ,EAAK,QAAQI,KAAS,GAAG;AACnD,UAAMC,IAAOL,EAAKI,CAAK;AACvB,IAAIC,MAAS,MACXH,KAAS,IACAG,MAAS,MAClBH,KAAS,IACAG,MAAS,OAAOH,MAAU,MACnCD,EAAM,KAAKD,EAAK,MAAMG,GAAOC,CAAK,EAAE,MAAM,GAC1CD,IAAQC,IAAQ;AAAA,EAEpB;AAEA,SAAAH,EAAM,KAAKD,EAAK,MAAMG,CAAK,EAAE,MAAM,GAC5BF;AACT;AAEA,SAASK,EAAmCX,GAAc;AAExD,QAAMY,IAAaZ,EAAK,QADJ,gBACuB,GACrCa,IAAYb,EAAK,QAAQ,KAAKY,CAAU,GACxCE,IAAUd,EAAK,YAAY,GAAG,GAC9Be,IAAwB;AAE9B,MAAIH,IAAa,KAAKC,IAAY,KAAKC,KAAWD;AAChD,UAAM,IAAI,MAAM,qCAAqCb,CAAI,EAAE;AAG7D,QAAM,CAACgB,GAASC,CAAS,IAAIb,EAAsBJ,EAAK,MAAMa,IAAY,GAAGC,CAAO,CAAC;AACrF,MAAI,CAACE,GAAS,SAASD,CAAqB,KAAK,CAACE,GAAW,SAAS,cAAc;AAClF,UAAM,IAAI,MAAM,+CAA+CjB,CAAI,EAAE;AAGvE,SAAOgB,EAAQ,MAAM,GAAG,CAACD,EAAsB,MAAM;AACvD;AAEA,SAASG,EAAchB,GAAe;AACpC,SAAO,WAAW,KAAK,KAAKA,CAAK,GAAG,CAACQ,MAASA,EAAK,WAAW,CAAC,CAAC;AAClE;AAEO,MAAMS,EAA0B;AAAA,EAIrC,YAAYC,GAAkBC,GAAgC;AAC5D,SAAK,WAAWD,EAAS,QAAQ,OAAO,EAAE,GAC1C,KAAK,UAAUC,GAAS,WAAW;AAAA,EACrC;AAAA,EAEA,MAAM,oBAAoBC,GAAsD;AAE9E,YADa,MAAM,KAAK,IAA+B,2BAA2BA,CAAQ,GAC9E,IAAI,CAACC,OAAU;AAAA,MACzB,IAAIA,EAAK;AAAA,MACT,mBAAmB,OAAO;AAAA,QACxB,OAAOA,EAAK,MAAM;AAAA,QAClB,MAAMA,EAAK,MAAM;AAAA,QACjB,MAAMA,EAAK,MAAM;AAAA,QACjB,aAAaA,EAAK,MAAM;AAAA,MAAA;AAAA,IAC1B,EACA;AAAA,EACJ;AAAA,EAEA,MAAM,wBAAwBD,GAA2C;AACvE,UAAME,IAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACAF;AAAA,MACA;AAAA,QACE,UAAU;AAAA,QACV,QAAQ;AAAA,MAAA;AAAA,IACV,GAEIG,IAAWD,EAAS,QAAQ,UAC5BE,IAAOF,EAAS,QAAQ,QAAQ,CAAA;AAEtC,QAAIC,KAAYA,MAAa;AAC3B,YAAM,IAAI,MAAM,6CAA6CA,CAAQ,EAAE;AAGzE,QAAIC,EAAK,WAAW;AAClB,YAAM,IAAI,MAAM,iEAAiE;AAGnF,WAAOA,EAAK,IAAIR,CAAa;AAAA,EAC/B;AAAA,EAEA,MAAc,IACZS,GACAL,GACAM,GACY;AACZ,UAAMC,IAAa,IAAI,gBAAA,GACjBC,IAAU,WAAW,MAAMD,EAAW,MAAA,GAAS,KAAK,OAAO,GAC3DE,IAAM,IAAI,IAAI,GAAG,KAAK,QAAQ,GAAGJ,CAAQ,EAAE;AAEjD,eAAW,CAACK,GAAK9B,CAAK,KAAK,OAAO,QAAQ0B,KAAgB,CAAA,CAAE;AAC1D,MAAAG,EAAI,aAAa,IAAIC,GAAK9B,CAAK;AAGjC,eAAWb,KAAWiC;AACpB,MAAAS,EAAI,aAAa,OAAO,SAAS3C,EAAiBC,CAAO,CAAC;AAG5D,QAAI;AACF,YAAM4C,IAAM,MAAM,MAAMF,GAAK;AAAA,QAC3B,QAAQF,EAAW;AAAA,MAAA,CACpB;AACD,UAAI,CAACI,EAAI;AACP,cAAM,IAAI,MAAM,0BAA0BA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE;AAE1E,aAAQ,MAAMA,EAAI,KAAA;AAAA,IACpB,UAAA;AACE,mBAAaH,CAAO;AAAA,IACtB;AAAA,EACF;AACF;AAEO,MAAMI,EAAc;AAAA,EAUzB,YACmBC,GACAC,GACAC,GACjB;AAHiB,SAAA,WAAAF,GACA,KAAA,cAAAC,GACA,KAAA,kBAAAC,GANnB,KAAiB,6CAA6B,IAAA;AAAA,EAO3C;AAAA,EAEK,kBAA8C;AACpD,UAAMC,IAAO,KAAK,SAAS;AAC3B,WACEA,KACA,OAAOA,EAAK,aAAc,cAC1B,OAAOA,EAAK,yBAA0B,cACtC,OAAOA,EAAK,mBAAoB,aAEzBA,IAEF;AAAA,EACT;AAAA,EAEA,MAAc,kBAAkBC,GAAkB;AAChD,UAAMD,IAAO,KAAK,gBAAA;AAClB,QAAIA,GAAM;AACR,YAAME,IAAS,MAAMF,EAAK,UAAU;AAAA,QAClC,UAAAC;AAAA,QACA,SAAS,EAAE,MAAM,GAAA;AAAA,MAAK,CACvB;AACD,aAAKC,EAAO,SAGL;AAAA,QACL,UAAUA,EAAO,OAAO;AAAA,QACxB,MAAMA,EAAO,OAAO;AAAA,QACpB,QAAQA,EAAO,OAAO;AAAA,MAAA,IALf;AAAA,IAOX;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,MAAM,8CAA8C;AAEhE,UAAMA,IAAS,MAAM,KAAK,SAAS,UAAU;AAAA,MAC3C,IAAID;AAAA,MACJ,SAAS,EAAE,aAAa,GAAA;AAAA,IAAK,CAC9B;AACD,WAAI,CAACC,EAAO,QAAQ,CAACA,EAAO,KAAK,WAAWA,EAAO,KAAK,QAAQ,aAAa,eACpE,OAEF;AAAA,MACL,UAAUA,EAAO,KAAK;AAAA,MACtB,MAAMA,EAAO,KAAK;AAAA,MAClB,QAAQA,EAAO,KAAK,QAAQ;AAAA,IAAA;AAAA,EAEhC;AAAA,EAEA,MAAc,yBAAyBC,GAAkBC,GAAkC;AACzF,UAAMJ,IAAO,KAAK,gBAAA;AAClB,QAAIA,GAAM;AACR,YAAME,IAAS,MAAMF,EAAK,sBAAsB;AAAA,QAC9C,UAAAG;AAAA,QACA,MAAAC;AAAA,QACA,SAAS,EAAE,MAAM,GAAA;AAAA,MAAK,CACvB;AACD,aAAKF,EAAO,SAGL;AAAA,QACL,UAAUA,EAAO,OAAO;AAAA,QACxB,MAAMA,EAAO,OAAO;AAAA,QACpB,QAAQA,EAAO,OAAO;AAAA,MAAA,IALf;AAAA,IAOX;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,MAAM,0DAA0D;AAE5E,UAAMA,IAAS,MAAM,KAAK,SAAS,sBAAsB;AAAA,MACvD,UAAAC;AAAA,MACA,MAAAC;AAAA,IAAA,CACD;AACD,WAAKF,EAAO,OAGPA,EAAO,KAAK,UAObA,EAAO,KAAK,QAAQ,aAAa,eAC5B,OAEF;AAAA,MACL,UAAUA,EAAO,KAAK;AAAA,MACtB,MAAMA,EAAO,KAAK;AAAA,MAClB,QAAQA,EAAO,KAAK,QAAQ;AAAA,IAAA,IAZrB;AAAA,MACL,UAAUA,EAAO,KAAK;AAAA,MACtB,MAAMA,EAAO,KAAK;AAAA,MAClB,QAAQ;AAAA,IAAA,IANH;AAAA,EAiBX;AAAA,EAEA,MAAM,iBAAiBG,GAAiBC,GAAuBC,GAAmB;AAChF,UAAMC,IAAY,MAAM,KAAK,iBAAA,GACvBC,IAAwB,MAAM,KAAK,0BAA0BJ,GAAIC,GAASE,CAAS,GACnFE,IAAgB,MAAM,KAAK,iBAAA,GAC3BC,IAAQN,EAAG;AAAA,MACfA,EAAG;AAAA,MACHE,EAAQ,IAAI,MAAMF,EAAG,KAAK,IAAIK,CAAa,CAAC;AAAA,IAAA;AAE9C,WAAO,KAAK,wBAAwBL,GAAIG,GAAWD,GAASE,GAAuBE,CAAK;AAAA,EAC1F;AAAA,EAEA,MAAc,mBAAmB;AAC/B,QAAI,KAAK,kBAAkB,QAAW;AACpC,YAAMT,IAAS,MAAM,KAAK,kBAAkB,KAAK,WAAW;AAC5D,UAAI,CAACA,GAAQ;AACX,cAAM,IAAI,MAAM,mCAAmC;AAErD,WAAK,gBAAgB,OAAQA,EAAO,OAAe,eAAe;AAAA,IACpE;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,aAAaD,GAAkB;AAC3C,UAAMC,IAAS,MAAM,KAAK,kBAAkBD,CAAQ;AACpD,QAAIC,GAAQ,QAAQ;AAClB,YAAMU,IAASV,EAAO;AACtB,UAAI,iBAAiBU,GAAQ;AAK3B,cAAMC,IAAaD,EAAO,aACpBJ,IAAYK,GAAY,WAAWA,GAAY,QAAQ;AAC7D,YAAIL;AACF,iBAAOA;AAAA,MAEX;AAAA,IACF;AACA,UAAM,IAAI,MAAM,sCAAsCP,CAAQ,EAAE;AAAA,EAClE;AAAA,EAEA,MAAc,WAAWa,GAAoBT,GAAiB;AAC5D,UAAMU,IAAoB,MAAM,KAAK,qBAAA;AACrC,WAAOD,EAAK,IAAI,CAACE,MAAQ;AACvB,YAAM,CAACC,CAAW,IAAIZ,EAAG,SAAS;AAAA,QAChC,QAAQ,GAAGU,CAAiB;AAAA,QAC5B,WAAW;AAAA,UACTV,EAAG,OAAO,KAAK,eAAe;AAAA,UAC9BA,EAAG,KAAK9C,EAAYyD,CAAG,CAAC;AAAA,UACxBX,EAAG,OAAOa,CAAmB;AAAA,QAAA;AAAA,MAC/B,CACD;AACD,aAAOD;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,0BACZZ,GACAC,GACAE,GACA;AACA,QAAIF,EAAQ,SAAS;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAGJ,UAAMU,IAAM,KAAK,sCAAsCV,EAAQ,CAAC,CAAC,GAC3D,CAACW,CAAW,IAAI,MAAM,KAAK,WAAW,CAACD,CAAG,GAAGX,CAAE,GAC/C,CAACI,CAAqB,IAAIJ,EAAG,SAAS;AAAA,MAC1C,QAAQ,GAAGG,CAAS;AAAA,MACpB,WAAW;AAAA,QACTH,EAAG,OAAO,KAAK,WAAW;AAAA,QAC1BA,EAAG,KAAK9C,EAAY+C,EAAQ,CAAC,CAAC,CAAC;AAAA,QAC/BW;AAAA,QACAZ,EAAG,OAAOa,CAAmB;AAAA,MAAA;AAAA,IAC/B,CACD;AACD,WAAOT;AAAA,EACT;AAAA,EAEA,MAAc,wBACZJ,GACAG,GACAD,GACAE,GACAE,GACA;AACA,UAAMQ,IAA6B,CAAA;AACnC,eAAW,CAACC,GAAQC,CAAM,KAAKd,EAAQ,WAAW;AAChD,YAAMe,IAAoB,MAAM,KAAK,qBAAqBD,CAAM;AAChE,UAAI,CAACC;AACH,cAAM,IAAI,MAAM,cAAcD,CAAM,oCAAoC;AAE1E,MAAAF,EAAiB,KAAKG,CAAiB,GACtC,CAACb,CAAqB,IAAIJ,EAAG,SAAS;AAAA,QACrC,QAAQ,GAAGG,CAAS;AAAA,QACpB,WAAW;AAAA,UACTH,EAAG,OAAO,KAAK,WAAW;AAAA,UAC1BI;AAAA,UACAJ,EAAG,OAAOiB,CAAiB;AAAA,UAC3BX,EAAMS,CAAM;AAAA,UACZf,EAAG,OAAOa,CAAmB;AAAA,QAAA;AAAA,MAC/B,CACD;AAAA,IACH;AACA,WAAAb,EAAG,SAAS;AAAA,MACV,QAAQ,GAAGG,CAAS;AAAA,MACpB,WAAW,CAACC,CAAqB;AAAA,MACjC,eAAe,CAAC,GAAGD,CAAS,yBAAyB;AAAA,IAAA,CACtD,GACMW;AAAA,EACT;AAAA,EAEA,MAAc,uBAAuB;AACnC,WAAK,KAAK,sBACR,KAAK,oBAAoB,MAAM,KAAK,aAAa,KAAK,eAAe,IAEhE,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,mBAAmB;AAC/B,WAAK,KAAK,kBACR,KAAK,gBAAgB,MAAM,KAAK,aAAa,KAAK,WAAW,IAExD,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,qBAAqBE,GAAgB;AACjD,UAAME,IAAmBzE,EAAiBuE,CAAM;AAChD,QAAI,CAAC,KAAK,uBAAuB,IAAIE,CAAgB,GAAG;AACtD,YAAM,EAAE,IAAIC,GAAS,WAAAC,MAAc,MAAM,KAAK,kBAAA,GACxCC,IAAW,GAAGD,CAAS,uCAEvBzB,IAAO,KAAK,gBAAA;AAClB,UAAIA,GAAM;AAMR,cAAM,EAAE,cAAA2B,EAAA,IAAiB,MAAM3B,EAAK,gBAAgB;AAAA,UAClD,UAAUwB;AAAA,UACV,MAAM/D,EAAmBiE,GAAU7D,EAAsBb,EAAWuE,CAAgB,CAAC,CAAC;AAAA,QAAA,CACvF,GACKK,IAAWD,GAAc,OAAO;AACtC,aAAK,uBAAuB;AAAA,UAC1BJ;AAAA,UACAK,KAAYA,EAAS,WAAW,KAC5BpE,EAAI,QAAQ,MAAM,WAAW,KAAKoE,CAAQ,CAAC,IAC3C;AAAA,QAAA;AAAA,MAER,OAAO;AACL,cAAM1B,IAAS,MAAM,KAAK,yBAAyBsB,GAAS;AAAA,UAC1D,MAAME;AAAA,UACN,OAAO;AAAA,YACL,OAAO,MAAM,KAAK1E,EAAWuE,CAAgB,CAAC;AAAA,UAAA;AAAA,QAChD,CACD;AACD,QAAKrB,GAAQ,SAGX,KAAK,uBAAuB,IAAIqB,GAAmBrB,EAAO,OAAe,KAAK,IAF9E,KAAK,uBAAuB,IAAIqB,GAAkB,MAAS;AAAA,MAI/D;AAAA,IACF;AACA,WAAO,KAAK,uBAAuB,IAAIA,CAAgB;AAAA,EACzD;AAAA,EAEA,MAAc,oBAAoB;AAChC,QAAI,CAAC,KAAK,gBAAgB;AACxB,YAAMM,IAAY,KAAK,gBAAA,IACnBpE,EAAmB,cAAcE,EAAe,YAAY,CAAC,IAC7D;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA,GAEPuC,IAAS,MAAM,KAAK,yBAAyB,KAAK,aAAa2B,CAAS;AAC9E,UAAI,CAAC3B,GAAQ;AACX,cAAM,IAAI,MAAM,wDAAwD;AAE1E,WAAK,iBAAiB;AAAA,QACpB,IAAIA,EAAO;AAAA,QACX,WAAW7B,EAAmC6B,EAAO,IAAI;AAAA,MAAA;AAAA,IAE7D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,sCAAsC4B,GAAgC;AAE5E,UAAMC,IAAgB,IADMD,EAAmB,CAAC,IACA,GAC1CE,IAAU3E,EAAayE,GAAoBC,CAAa,GACxDE,IAAYF,IAAgB;AAClC,WAAOD,EAAmB,SAASG,GAAWA,IAAYD,CAAO;AAAA,EACnE;AACF;"}
|
|
1
|
+
{"version":3,"file":"pyth.js","sources":["../src/pyth.ts"],"sourcesContent":["import type { NaviSuiClient } from './sui'\nimport type { TransactionObjectArgument } from '@mysten/sui/transactions'\nimport { Transaction } from '@mysten/sui/transactions'\nimport { bcs } from '@mysten/sui/bcs'\nimport { SUI_CLOCK_OBJECT_ID } from '@mysten/sui/utils'\n\ntype HermesPrice = {\n price: string\n conf: string\n expo: number\n publish_time: number\n}\n\ntype HermesPriceFeedResponse = {\n id: string\n price: HermesPrice\n}\n\ntype HermesPriceUpdateResponse = {\n binary?: {\n encoding?: string\n data?: string[]\n }\n}\n\ntype PriceFeed = {\n id: string\n getPriceUnchecked(): {\n price: string\n conf: string\n expo: number\n publishTime: number\n }\n}\n\ntype CoreDynamicFieldName = {\n type: string\n bcs: Uint8Array\n}\n\ntype SuiPythProvider = Partial<Pick<NaviSuiClient, 'getObject' | 'getDynamicFieldObject'>> & {\n core?: unknown\n}\n\ntype SuiPythCoreProvider = {\n getObject(options: {\n objectId: string\n include?: { json?: boolean; content?: boolean }\n }): Promise<{\n object?: { objectId: string; type?: string; json?: Record<string, unknown> | null }\n }>\n getDynamicObjectField(options: {\n parentId: string\n name: CoreDynamicFieldName\n include?: { json?: boolean; content?: boolean }\n }): Promise<{\n object?: { objectId: string; type?: string; json?: Record<string, unknown> | null }\n }>\n getDynamicField(options: { parentId: string; name: CoreDynamicFieldName }): Promise<{\n dynamicField?: { value?: { type?: string; bcs?: Uint8Array } }\n }>\n}\n\nconst MAX_ARGUMENT_SIZE = 16 * 1024\n\nfunction normalizePriceId(priceId: string) {\n return priceId.replace(/^0x/i, '')\n}\n\nfunction hexToBytes(hex: string) {\n const normalized = normalizePriceId(hex)\n const bytes = new Uint8Array(normalized.length / 2)\n for (let i = 0; i < bytes.length; i += 1) {\n bytes[i] = parseInt(normalized.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\nfunction readUint16BE(bytes: Uint8Array, offset: number) {\n return (bytes[offset] << 8) + bytes[offset + 1]\n}\n\nfunction toPureBytes(bytes: Uint8Array) {\n return bcs.vector(bcs.U8).serialize(Array.from(bytes), {\n maxSize: MAX_ARGUMENT_SIZE\n })\n}\n\nfunction toDynamicFieldName(type: string, bytes: Uint8Array): CoreDynamicFieldName {\n return {\n type,\n bcs: bytes\n }\n}\n\nfunction encodeVectorU8(value: string) {\n return bcs\n .vector(bcs.U8)\n .serialize(Array.from(new TextEncoder().encode(value)))\n .toBytes()\n}\n\nfunction encodePriceIdentifier(bytes: Uint8Array) {\n return bcs\n .struct('PriceIdentifier', {\n bytes: bcs.vector(bcs.U8)\n })\n .serialize({\n bytes: Array.from(bytes)\n })\n .toBytes()\n}\n\nfunction splitTopLevelTypeArgs(args: string) {\n const parts: string[] = []\n let depth = 0\n let start = 0\n\n for (let index = 0; index < args.length; index += 1) {\n const char = args[index]\n if (char === '<') {\n depth += 1\n } else if (char === '>') {\n depth -= 1\n } else if (char === ',' && depth === 0) {\n parts.push(args.slice(start, index).trim())\n start = index + 1\n }\n }\n\n parts.push(args.slice(start).trim())\n return parts\n}\n\nfunction getPythPackageIdFromPriceTableType(type: string) {\n const tablePrefix = '::table::Table'\n const tableIndex = type.indexOf(tablePrefix)\n const argsStart = type.indexOf('<', tableIndex)\n const argsEnd = type.lastIndexOf('>')\n const priceIdentifierSuffix = '::price_identifier::PriceIdentifier'\n\n if (tableIndex < 0 || argsStart < 0 || argsEnd <= argsStart) {\n throw new Error(`Unexpected Pyth price table type: ${type}`)\n }\n\n const [keyType, valueType] = splitTopLevelTypeArgs(type.slice(argsStart + 1, argsEnd))\n if (!keyType?.endsWith(priceIdentifierSuffix) || !valueType?.endsWith('::object::ID')) {\n throw new Error(`Unexpected Pyth price table type arguments: ${type}`)\n }\n\n return keyType.slice(0, -priceIdentifierSuffix.length)\n}\n\nfunction base64ToBytes(value: string) {\n return Uint8Array.from(atob(value), (char) => char.charCodeAt(0))\n}\n\nexport class SuiPriceServiceConnection {\n private readonly endpoint: string\n private readonly timeout: number\n\n constructor(endpoint: string, options?: { timeout?: number }) {\n this.endpoint = endpoint.replace(/\\/$/, '')\n this.timeout = options?.timeout ?? 10000\n }\n\n async getLatestPriceFeeds(priceIds: string[]): Promise<PriceFeed[] | undefined> {\n const data = await this.get<HermesPriceFeedResponse[]>('/api/latest_price_feeds', priceIds)\n return data.map((feed) => ({\n id: feed.id,\n getPriceUnchecked: () => ({\n price: feed.price.price,\n conf: feed.price.conf,\n expo: feed.price.expo,\n publishTime: feed.price.publish_time\n })\n }))\n }\n\n async getPriceFeedsUpdateData(priceIds: string[]): Promise<Uint8Array[]> {\n const response = await this.get<HermesPriceUpdateResponse>(\n '/v2/updates/price/latest',\n priceIds,\n {\n encoding: 'base64',\n parsed: 'false'\n }\n )\n const encoding = response.binary?.encoding\n const data = response.binary?.data ?? []\n\n if (encoding && encoding !== 'base64') {\n throw new Error(`Unsupported Hermes price update encoding: ${encoding}`)\n }\n\n if (data.length === 0) {\n throw new Error('Hermes price update response did not include binary update data')\n }\n\n return data.map(base64ToBytes)\n }\n\n private async get<T>(\n pathname: string,\n priceIds: string[],\n searchParams?: Record<string, string>\n ): Promise<T> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), this.timeout)\n const url = new URL(`${this.endpoint}${pathname}`)\n\n for (const [key, value] of Object.entries(searchParams ?? {})) {\n url.searchParams.set(key, value)\n }\n\n for (const priceId of priceIds) {\n url.searchParams.append('ids[]', normalizePriceId(priceId))\n }\n\n try {\n const res = await fetch(url, {\n signal: controller.signal\n })\n if (!res.ok) {\n throw new Error(`Hermes request failed: ${res.status} ${res.statusText}`)\n }\n return (await res.json()) as T\n } finally {\n clearTimeout(timeout)\n }\n }\n}\n\nexport class SuiPythClient {\n private pythPackageId?: string\n private wormholePackageId?: string\n private priceTableInfo?: {\n id: string\n fieldType: string\n }\n private readonly priceFeedObjectIdCache = new Map<string, string | undefined>()\n private baseUpdateFee?: number\n\n constructor(\n private readonly provider: SuiPythProvider,\n private readonly pythStateId: string,\n private readonly wormholeStateId: string\n ) {}\n\n private getCoreProvider(): SuiPythCoreProvider | null {\n const core = this.provider.core as Partial<SuiPythCoreProvider> | undefined\n if (\n core &&\n typeof core.getObject === 'function' &&\n typeof core.getDynamicObjectField === 'function' &&\n typeof core.getDynamicField === 'function'\n ) {\n return core as SuiPythCoreProvider\n }\n return null\n }\n\n private async getMoveObjectJson(objectId: string) {\n const core = this.getCoreProvider()\n if (core) {\n const result = await core.getObject({\n objectId,\n include: { json: true }\n })\n if (!result.object) {\n return null\n }\n return {\n objectId: result.object.objectId,\n type: result.object.type,\n fields: result.object.json\n }\n }\n\n if (!this.provider.getObject) {\n throw new Error('Sui Pyth provider does not support getObject')\n }\n const result = await this.provider.getObject({\n id: objectId,\n options: { showContent: true }\n })\n if (!result.data || !result.data.content || result.data.content.dataType !== 'moveObject') {\n return null\n }\n return {\n objectId: result.data.objectId,\n type: result.data.type,\n fields: result.data.content.fields as Record<string, unknown>\n }\n }\n\n private async getDynamicMoveObjectJson(parentId: string, name: CoreDynamicFieldName | any) {\n const core = this.getCoreProvider()\n if (core) {\n const result = await core.getDynamicObjectField({\n parentId,\n name,\n include: { json: true }\n })\n if (!result.object) {\n return null\n }\n return {\n objectId: result.object.objectId,\n type: result.object.type,\n fields: result.object.json\n }\n }\n\n if (!this.provider.getDynamicFieldObject) {\n throw new Error('Sui Pyth provider does not support getDynamicFieldObject')\n }\n const result = await this.provider.getDynamicFieldObject({\n parentId,\n name\n })\n if (!result.data) {\n return null\n }\n if (!result.data.content) {\n return {\n objectId: result.data.objectId,\n type: result.data.type,\n fields: undefined\n }\n }\n if (result.data.content.dataType !== 'moveObject') {\n return null\n }\n return {\n objectId: result.data.objectId,\n type: result.data.type,\n fields: result.data.content.fields as Record<string, unknown>\n }\n }\n\n async updatePriceFeeds(\n tx: Transaction,\n updates: Uint8Array[],\n feedIds: string[],\n options?: { feeCoin?: TransactionObjectArgument }\n ) {\n const packageId = await this.getPythPackageId()\n const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId)\n const baseUpdateFee = await this.getBaseUpdateFee()\n const coins = tx.splitCoins(\n options?.feeCoin ?? tx.gas,\n feedIds.map(() => tx.pure.u64(baseUpdateFee))\n )\n return this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins)\n }\n\n private async getBaseUpdateFee() {\n if (this.baseUpdateFee === undefined) {\n const result = await this.getMoveObjectJson(this.pythStateId)\n if (!result?.fields) {\n throw new Error('Unable to fetch pyth state object')\n }\n this.baseUpdateFee = Number((result.fields as any).base_update_fee)\n }\n return this.baseUpdateFee\n }\n\n private async getPackageId(objectId: string) {\n const result = await this.getMoveObjectJson(objectId)\n if (result?.fields) {\n const fields = result.fields as any\n if ('upgrade_cap' in fields) {\n // Sui v2 Core (gRPC) returns flat json (upgrade_cap.package) while legacy\n // JSON-RPC nests it (upgrade_cap.fields.package). Support both; otherwise\n // the Core path cannot resolve the packageId and getPythPackageId /\n // getWormholePackageId throw, breaking Pyth price feed updates entirely.\n const upgradeCap = fields.upgrade_cap\n const packageId = upgradeCap?.package ?? upgradeCap?.fields?.package\n if (packageId) {\n return packageId as string\n }\n }\n }\n throw new Error(`Cannot fetch package id for object ${objectId}`)\n }\n\n private async verifyVaas(vaas: Uint8Array[], tx: Transaction) {\n const wormholePackageId = await this.getWormholePackageId()\n return vaas.map((vaa) => {\n const [verifiedVaa] = tx.moveCall({\n target: `${wormholePackageId}::vaa::parse_and_verify`,\n arguments: [\n tx.object(this.wormholeStateId),\n tx.pure(toPureBytes(vaa)),\n tx.object(SUI_CLOCK_OBJECT_ID)\n ]\n })\n return verifiedVaa\n })\n }\n\n private async verifyVaasAndGetHotPotato(\n tx: Transaction,\n updates: Uint8Array[],\n packageId: string\n ) {\n if (updates.length > 1) {\n throw new Error(\n 'SDK does not support sending multiple accumulator messages in a single transaction'\n )\n }\n const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0])\n const [verifiedVaa] = await this.verifyVaas([vaa], tx)\n const [priceUpdatesHotPotato] = tx.moveCall({\n target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,\n arguments: [\n tx.object(this.pythStateId),\n tx.pure(toPureBytes(updates[0])),\n verifiedVaa,\n tx.object(SUI_CLOCK_OBJECT_ID)\n ]\n })\n return priceUpdatesHotPotato\n }\n\n private async executePriceFeedUpdates(\n tx: Transaction,\n packageId: string,\n feedIds: string[],\n priceUpdatesHotPotato: any,\n coins: any[]\n ) {\n const priceInfoObjects: string[] = []\n for (const [coinId, feedId] of feedIds.entries()) {\n const priceInfoObjectId = await this.getPriceFeedObjectId(feedId)\n if (!priceInfoObjectId) {\n throw new Error(`Price feed ${feedId} not found, please create it first`)\n }\n priceInfoObjects.push(priceInfoObjectId)\n ;[priceUpdatesHotPotato] = tx.moveCall({\n target: `${packageId}::pyth::update_single_price_feed`,\n arguments: [\n tx.object(this.pythStateId),\n priceUpdatesHotPotato,\n tx.object(priceInfoObjectId),\n coins[coinId],\n tx.object(SUI_CLOCK_OBJECT_ID)\n ]\n })\n }\n tx.moveCall({\n target: `${packageId}::hot_potato_vector::destroy`,\n arguments: [priceUpdatesHotPotato],\n typeArguments: [`${packageId}::price_info::PriceInfo`]\n })\n return priceInfoObjects\n }\n\n private async getWormholePackageId() {\n if (!this.wormholePackageId) {\n this.wormholePackageId = await this.getPackageId(this.wormholeStateId)\n }\n return this.wormholePackageId\n }\n\n private async getPythPackageId() {\n if (!this.pythPackageId) {\n this.pythPackageId = await this.getPackageId(this.pythStateId)\n }\n return this.pythPackageId\n }\n\n private async getPriceFeedObjectId(feedId: string) {\n const normalizedFeedId = normalizePriceId(feedId)\n if (!this.priceFeedObjectIdCache.has(normalizedFeedId)) {\n const { id: tableId, fieldType } = await this.getPriceTableInfo()\n const nameType = `${fieldType}::price_identifier::PriceIdentifier`\n\n const core = this.getCoreProvider()\n if (core) {\n // Pyth's price table stores entries as plain dynamic fields\n // (0x2::dynamic_field::Field<PriceIdentifier, ID>). getDynamicObjectField\n // must not be used here: it derives the child id from\n // Wrapper<PriceIdentifier> and resolves to an object that does not exist\n // on chain, aborting every Pyth price feed update.\n const { dynamicField } = await core.getDynamicField({\n parentId: tableId,\n name: toDynamicFieldName(nameType, encodePriceIdentifier(hexToBytes(normalizedFeedId)))\n })\n const valueBcs = dynamicField?.value?.bcs\n this.priceFeedObjectIdCache.set(\n normalizedFeedId,\n valueBcs && valueBcs.length === 32\n ? bcs.Address.parse(Uint8Array.from(valueBcs))\n : undefined\n )\n } else {\n const result = await this.getDynamicMoveObjectJson(tableId, {\n type: nameType,\n value: {\n bytes: Array.from(hexToBytes(normalizedFeedId))\n }\n })\n if (!result?.fields) {\n this.priceFeedObjectIdCache.set(normalizedFeedId, undefined)\n } else {\n this.priceFeedObjectIdCache.set(normalizedFeedId, (result.fields as any).value)\n }\n }\n }\n return this.priceFeedObjectIdCache.get(normalizedFeedId)\n }\n\n private async getPriceTableInfo() {\n if (!this.priceTableInfo) {\n const fieldName = this.getCoreProvider()\n ? toDynamicFieldName('vector<u8>', encodeVectorU8('price_info'))\n : {\n type: 'vector<u8>',\n value: 'price_info'\n }\n const result = await this.getDynamicMoveObjectJson(this.pythStateId, fieldName)\n if (!result?.type) {\n throw new Error('Price Table not found, contract may not be initialized')\n }\n this.priceTableInfo = {\n id: result.objectId,\n fieldType: getPythPackageIdFromPriceTableType(result.type)\n }\n }\n return this.priceTableInfo\n }\n\n private extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Uint8Array) {\n const trailingPayloadSize = accumulatorMessage[6]\n const vaaSizeOffset = 7 + trailingPayloadSize + 1\n const vaaSize = readUint16BE(accumulatorMessage, vaaSizeOffset)\n const vaaOffset = vaaSizeOffset + 2\n return accumulatorMessage.subarray(vaaOffset, vaaOffset + vaaSize)\n }\n}\n"],"names":["MAX_ARGUMENT_SIZE","normalizePriceId","priceId","hexToBytes","hex","normalized","bytes","i","readUint16BE","offset","toPureBytes","bcs","toDynamicFieldName","type","encodeVectorU8","value","encodePriceIdentifier","splitTopLevelTypeArgs","args","parts","depth","start","index","char","getPythPackageIdFromPriceTableType","tableIndex","argsStart","argsEnd","priceIdentifierSuffix","keyType","valueType","base64ToBytes","SuiPriceServiceConnection","endpoint","options","priceIds","feed","response","encoding","data","pathname","searchParams","controller","timeout","url","key","res","SuiPythClient","provider","pythStateId","wormholeStateId","core","objectId","result","parentId","name","tx","updates","feedIds","packageId","priceUpdatesHotPotato","baseUpdateFee","coins","fields","upgradeCap","vaas","wormholePackageId","vaa","verifiedVaa","SUI_CLOCK_OBJECT_ID","priceInfoObjects","coinId","feedId","priceInfoObjectId","normalizedFeedId","tableId","fieldType","nameType","dynamicField","valueBcs","fieldName","accumulatorMessage","vaaSizeOffset","vaaSize","vaaOffset"],"mappings":";;AA+DA,MAAMA,IAAoB,KAAK;AAE/B,SAASC,EAAiBC,GAAiB;AACzC,SAAOA,EAAQ,QAAQ,QAAQ,EAAE;AACnC;AAEA,SAASC,EAAWC,GAAa;AAC/B,QAAMC,IAAaJ,EAAiBG,CAAG,GACjCE,IAAQ,IAAI,WAAWD,EAAW,SAAS,CAAC;AAClD,WAASE,IAAI,GAAGA,IAAID,EAAM,QAAQC,KAAK;AACrC,IAAAD,EAAMC,CAAC,IAAI,SAASF,EAAW,MAAME,IAAI,GAAGA,IAAI,IAAI,CAAC,GAAG,EAAE;AAE5D,SAAOD;AACT;AAEA,SAASE,EAAaF,GAAmBG,GAAgB;AACvD,UAAQH,EAAMG,CAAM,KAAK,KAAKH,EAAMG,IAAS,CAAC;AAChD;AAEA,SAASC,EAAYJ,GAAmB;AACtC,SAAOK,EAAI,OAAOA,EAAI,EAAE,EAAE,UAAU,MAAM,KAAKL,CAAK,GAAG;AAAA,IACrD,SAASN;AAAA,EAAA,CACV;AACH;AAEA,SAASY,EAAmBC,GAAcP,GAAyC;AACjF,SAAO;AAAA,IACL,MAAAO;AAAA,IACA,KAAKP;AAAA,EAAA;AAET;AAEA,SAASQ,EAAeC,GAAe;AACrC,SAAOJ,EACJ,OAAOA,EAAI,EAAE,EACb,UAAU,MAAM,KAAK,IAAI,YAAA,EAAc,OAAOI,CAAK,CAAC,CAAC,EACrD,QAAA;AACL;AAEA,SAASC,EAAsBV,GAAmB;AAChD,SAAOK,EACJ,OAAO,mBAAmB;AAAA,IACzB,OAAOA,EAAI,OAAOA,EAAI,EAAE;AAAA,EAAA,CACzB,EACA,UAAU;AAAA,IACT,OAAO,MAAM,KAAKL,CAAK;AAAA,EAAA,CACxB,EACA,QAAA;AACL;AAEA,SAASW,EAAsBC,GAAc;AAC3C,QAAMC,IAAkB,CAAA;AACxB,MAAIC,IAAQ,GACRC,IAAQ;AAEZ,WAASC,IAAQ,GAAGA,IAAQJ,EAAK,QAAQI,KAAS,GAAG;AACnD,UAAMC,IAAOL,EAAKI,CAAK;AACvB,IAAIC,MAAS,MACXH,KAAS,IACAG,MAAS,MAClBH,KAAS,IACAG,MAAS,OAAOH,MAAU,MACnCD,EAAM,KAAKD,EAAK,MAAMG,GAAOC,CAAK,EAAE,MAAM,GAC1CD,IAAQC,IAAQ;AAAA,EAEpB;AAEA,SAAAH,EAAM,KAAKD,EAAK,MAAMG,CAAK,EAAE,MAAM,GAC5BF;AACT;AAEA,SAASK,EAAmCX,GAAc;AAExD,QAAMY,IAAaZ,EAAK,QADJ,gBACuB,GACrCa,IAAYb,EAAK,QAAQ,KAAKY,CAAU,GACxCE,IAAUd,EAAK,YAAY,GAAG,GAC9Be,IAAwB;AAE9B,MAAIH,IAAa,KAAKC,IAAY,KAAKC,KAAWD;AAChD,UAAM,IAAI,MAAM,qCAAqCb,CAAI,EAAE;AAG7D,QAAM,CAACgB,GAASC,CAAS,IAAIb,EAAsBJ,EAAK,MAAMa,IAAY,GAAGC,CAAO,CAAC;AACrF,MAAI,CAACE,GAAS,SAASD,CAAqB,KAAK,CAACE,GAAW,SAAS,cAAc;AAClF,UAAM,IAAI,MAAM,+CAA+CjB,CAAI,EAAE;AAGvE,SAAOgB,EAAQ,MAAM,GAAG,CAACD,EAAsB,MAAM;AACvD;AAEA,SAASG,EAAchB,GAAe;AACpC,SAAO,WAAW,KAAK,KAAKA,CAAK,GAAG,CAACQ,MAASA,EAAK,WAAW,CAAC,CAAC;AAClE;AAEO,MAAMS,EAA0B;AAAA,EAIrC,YAAYC,GAAkBC,GAAgC;AAC5D,SAAK,WAAWD,EAAS,QAAQ,OAAO,EAAE,GAC1C,KAAK,UAAUC,GAAS,WAAW;AAAA,EACrC;AAAA,EAEA,MAAM,oBAAoBC,GAAsD;AAE9E,YADa,MAAM,KAAK,IAA+B,2BAA2BA,CAAQ,GAC9E,IAAI,CAACC,OAAU;AAAA,MACzB,IAAIA,EAAK;AAAA,MACT,mBAAmB,OAAO;AAAA,QACxB,OAAOA,EAAK,MAAM;AAAA,QAClB,MAAMA,EAAK,MAAM;AAAA,QACjB,MAAMA,EAAK,MAAM;AAAA,QACjB,aAAaA,EAAK,MAAM;AAAA,MAAA;AAAA,IAC1B,EACA;AAAA,EACJ;AAAA,EAEA,MAAM,wBAAwBD,GAA2C;AACvE,UAAME,IAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACAF;AAAA,MACA;AAAA,QACE,UAAU;AAAA,QACV,QAAQ;AAAA,MAAA;AAAA,IACV,GAEIG,IAAWD,EAAS,QAAQ,UAC5BE,IAAOF,EAAS,QAAQ,QAAQ,CAAA;AAEtC,QAAIC,KAAYA,MAAa;AAC3B,YAAM,IAAI,MAAM,6CAA6CA,CAAQ,EAAE;AAGzE,QAAIC,EAAK,WAAW;AAClB,YAAM,IAAI,MAAM,iEAAiE;AAGnF,WAAOA,EAAK,IAAIR,CAAa;AAAA,EAC/B;AAAA,EAEA,MAAc,IACZS,GACAL,GACAM,GACY;AACZ,UAAMC,IAAa,IAAI,gBAAA,GACjBC,IAAU,WAAW,MAAMD,EAAW,MAAA,GAAS,KAAK,OAAO,GAC3DE,IAAM,IAAI,IAAI,GAAG,KAAK,QAAQ,GAAGJ,CAAQ,EAAE;AAEjD,eAAW,CAACK,GAAK9B,CAAK,KAAK,OAAO,QAAQ0B,KAAgB,CAAA,CAAE;AAC1D,MAAAG,EAAI,aAAa,IAAIC,GAAK9B,CAAK;AAGjC,eAAWb,KAAWiC;AACpB,MAAAS,EAAI,aAAa,OAAO,SAAS3C,EAAiBC,CAAO,CAAC;AAG5D,QAAI;AACF,YAAM4C,IAAM,MAAM,MAAMF,GAAK;AAAA,QAC3B,QAAQF,EAAW;AAAA,MAAA,CACpB;AACD,UAAI,CAACI,EAAI;AACP,cAAM,IAAI,MAAM,0BAA0BA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE;AAE1E,aAAQ,MAAMA,EAAI,KAAA;AAAA,IACpB,UAAA;AACE,mBAAaH,CAAO;AAAA,IACtB;AAAA,EACF;AACF;AAEO,MAAMI,EAAc;AAAA,EAUzB,YACmBC,GACAC,GACAC,GACjB;AAHiB,SAAA,WAAAF,GACA,KAAA,cAAAC,GACA,KAAA,kBAAAC,GANnB,KAAiB,6CAA6B,IAAA;AAAA,EAO3C;AAAA,EAEK,kBAA8C;AACpD,UAAMC,IAAO,KAAK,SAAS;AAC3B,WACEA,KACA,OAAOA,EAAK,aAAc,cAC1B,OAAOA,EAAK,yBAA0B,cACtC,OAAOA,EAAK,mBAAoB,aAEzBA,IAEF;AAAA,EACT;AAAA,EAEA,MAAc,kBAAkBC,GAAkB;AAChD,UAAMD,IAAO,KAAK,gBAAA;AAClB,QAAIA,GAAM;AACR,YAAME,IAAS,MAAMF,EAAK,UAAU;AAAA,QAClC,UAAAC;AAAA,QACA,SAAS,EAAE,MAAM,GAAA;AAAA,MAAK,CACvB;AACD,aAAKC,EAAO,SAGL;AAAA,QACL,UAAUA,EAAO,OAAO;AAAA,QACxB,MAAMA,EAAO,OAAO;AAAA,QACpB,QAAQA,EAAO,OAAO;AAAA,MAAA,IALf;AAAA,IAOX;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,MAAM,8CAA8C;AAEhE,UAAMA,IAAS,MAAM,KAAK,SAAS,UAAU;AAAA,MAC3C,IAAID;AAAA,MACJ,SAAS,EAAE,aAAa,GAAA;AAAA,IAAK,CAC9B;AACD,WAAI,CAACC,EAAO,QAAQ,CAACA,EAAO,KAAK,WAAWA,EAAO,KAAK,QAAQ,aAAa,eACpE,OAEF;AAAA,MACL,UAAUA,EAAO,KAAK;AAAA,MACtB,MAAMA,EAAO,KAAK;AAAA,MAClB,QAAQA,EAAO,KAAK,QAAQ;AAAA,IAAA;AAAA,EAEhC;AAAA,EAEA,MAAc,yBAAyBC,GAAkBC,GAAkC;AACzF,UAAMJ,IAAO,KAAK,gBAAA;AAClB,QAAIA,GAAM;AACR,YAAME,IAAS,MAAMF,EAAK,sBAAsB;AAAA,QAC9C,UAAAG;AAAA,QACA,MAAAC;AAAA,QACA,SAAS,EAAE,MAAM,GAAA;AAAA,MAAK,CACvB;AACD,aAAKF,EAAO,SAGL;AAAA,QACL,UAAUA,EAAO,OAAO;AAAA,QACxB,MAAMA,EAAO,OAAO;AAAA,QACpB,QAAQA,EAAO,OAAO;AAAA,MAAA,IALf;AAAA,IAOX;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,MAAM,0DAA0D;AAE5E,UAAMA,IAAS,MAAM,KAAK,SAAS,sBAAsB;AAAA,MACvD,UAAAC;AAAA,MACA,MAAAC;AAAA,IAAA,CACD;AACD,WAAKF,EAAO,OAGPA,EAAO,KAAK,UAObA,EAAO,KAAK,QAAQ,aAAa,eAC5B,OAEF;AAAA,MACL,UAAUA,EAAO,KAAK;AAAA,MACtB,MAAMA,EAAO,KAAK;AAAA,MAClB,QAAQA,EAAO,KAAK,QAAQ;AAAA,IAAA,IAZrB;AAAA,MACL,UAAUA,EAAO,KAAK;AAAA,MACtB,MAAMA,EAAO,KAAK;AAAA,MAClB,QAAQ;AAAA,IAAA,IANH;AAAA,EAiBX;AAAA,EAEA,MAAM,iBACJG,GACAC,GACAC,GACAxB,GACA;AACA,UAAMyB,IAAY,MAAM,KAAK,iBAAA,GACvBC,IAAwB,MAAM,KAAK,0BAA0BJ,GAAIC,GAASE,CAAS,GACnFE,IAAgB,MAAM,KAAK,iBAAA,GAC3BC,IAAQN,EAAG;AAAA,MACftB,GAAS,WAAWsB,EAAG;AAAA,MACvBE,EAAQ,IAAI,MAAMF,EAAG,KAAK,IAAIK,CAAa,CAAC;AAAA,IAAA;AAE9C,WAAO,KAAK,wBAAwBL,GAAIG,GAAWD,GAASE,GAAuBE,CAAK;AAAA,EAC1F;AAAA,EAEA,MAAc,mBAAmB;AAC/B,QAAI,KAAK,kBAAkB,QAAW;AACpC,YAAMT,IAAS,MAAM,KAAK,kBAAkB,KAAK,WAAW;AAC5D,UAAI,CAACA,GAAQ;AACX,cAAM,IAAI,MAAM,mCAAmC;AAErD,WAAK,gBAAgB,OAAQA,EAAO,OAAe,eAAe;AAAA,IACpE;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,aAAaD,GAAkB;AAC3C,UAAMC,IAAS,MAAM,KAAK,kBAAkBD,CAAQ;AACpD,QAAIC,GAAQ,QAAQ;AAClB,YAAMU,IAASV,EAAO;AACtB,UAAI,iBAAiBU,GAAQ;AAK3B,cAAMC,IAAaD,EAAO,aACpBJ,IAAYK,GAAY,WAAWA,GAAY,QAAQ;AAC7D,YAAIL;AACF,iBAAOA;AAAA,MAEX;AAAA,IACF;AACA,UAAM,IAAI,MAAM,sCAAsCP,CAAQ,EAAE;AAAA,EAClE;AAAA,EAEA,MAAc,WAAWa,GAAoBT,GAAiB;AAC5D,UAAMU,IAAoB,MAAM,KAAK,qBAAA;AACrC,WAAOD,EAAK,IAAI,CAACE,MAAQ;AACvB,YAAM,CAACC,CAAW,IAAIZ,EAAG,SAAS;AAAA,QAChC,QAAQ,GAAGU,CAAiB;AAAA,QAC5B,WAAW;AAAA,UACTV,EAAG,OAAO,KAAK,eAAe;AAAA,UAC9BA,EAAG,KAAK9C,EAAYyD,CAAG,CAAC;AAAA,UACxBX,EAAG,OAAOa,CAAmB;AAAA,QAAA;AAAA,MAC/B,CACD;AACD,aAAOD;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,0BACZZ,GACAC,GACAE,GACA;AACA,QAAIF,EAAQ,SAAS;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAGJ,UAAMU,IAAM,KAAK,sCAAsCV,EAAQ,CAAC,CAAC,GAC3D,CAACW,CAAW,IAAI,MAAM,KAAK,WAAW,CAACD,CAAG,GAAGX,CAAE,GAC/C,CAACI,CAAqB,IAAIJ,EAAG,SAAS;AAAA,MAC1C,QAAQ,GAAGG,CAAS;AAAA,MACpB,WAAW;AAAA,QACTH,EAAG,OAAO,KAAK,WAAW;AAAA,QAC1BA,EAAG,KAAK9C,EAAY+C,EAAQ,CAAC,CAAC,CAAC;AAAA,QAC/BW;AAAA,QACAZ,EAAG,OAAOa,CAAmB;AAAA,MAAA;AAAA,IAC/B,CACD;AACD,WAAOT;AAAA,EACT;AAAA,EAEA,MAAc,wBACZJ,GACAG,GACAD,GACAE,GACAE,GACA;AACA,UAAMQ,IAA6B,CAAA;AACnC,eAAW,CAACC,GAAQC,CAAM,KAAKd,EAAQ,WAAW;AAChD,YAAMe,IAAoB,MAAM,KAAK,qBAAqBD,CAAM;AAChE,UAAI,CAACC;AACH,cAAM,IAAI,MAAM,cAAcD,CAAM,oCAAoC;AAE1E,MAAAF,EAAiB,KAAKG,CAAiB,GACtC,CAACb,CAAqB,IAAIJ,EAAG,SAAS;AAAA,QACrC,QAAQ,GAAGG,CAAS;AAAA,QACpB,WAAW;AAAA,UACTH,EAAG,OAAO,KAAK,WAAW;AAAA,UAC1BI;AAAA,UACAJ,EAAG,OAAOiB,CAAiB;AAAA,UAC3BX,EAAMS,CAAM;AAAA,UACZf,EAAG,OAAOa,CAAmB;AAAA,QAAA;AAAA,MAC/B,CACD;AAAA,IACH;AACA,WAAAb,EAAG,SAAS;AAAA,MACV,QAAQ,GAAGG,CAAS;AAAA,MACpB,WAAW,CAACC,CAAqB;AAAA,MACjC,eAAe,CAAC,GAAGD,CAAS,yBAAyB;AAAA,IAAA,CACtD,GACMW;AAAA,EACT;AAAA,EAEA,MAAc,uBAAuB;AACnC,WAAK,KAAK,sBACR,KAAK,oBAAoB,MAAM,KAAK,aAAa,KAAK,eAAe,IAEhE,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,mBAAmB;AAC/B,WAAK,KAAK,kBACR,KAAK,gBAAgB,MAAM,KAAK,aAAa,KAAK,WAAW,IAExD,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,qBAAqBE,GAAgB;AACjD,UAAME,IAAmBzE,EAAiBuE,CAAM;AAChD,QAAI,CAAC,KAAK,uBAAuB,IAAIE,CAAgB,GAAG;AACtD,YAAM,EAAE,IAAIC,GAAS,WAAAC,MAAc,MAAM,KAAK,kBAAA,GACxCC,IAAW,GAAGD,CAAS,uCAEvBzB,IAAO,KAAK,gBAAA;AAClB,UAAIA,GAAM;AAMR,cAAM,EAAE,cAAA2B,EAAA,IAAiB,MAAM3B,EAAK,gBAAgB;AAAA,UAClD,UAAUwB;AAAA,UACV,MAAM/D,EAAmBiE,GAAU7D,EAAsBb,EAAWuE,CAAgB,CAAC,CAAC;AAAA,QAAA,CACvF,GACKK,IAAWD,GAAc,OAAO;AACtC,aAAK,uBAAuB;AAAA,UAC1BJ;AAAA,UACAK,KAAYA,EAAS,WAAW,KAC5BpE,EAAI,QAAQ,MAAM,WAAW,KAAKoE,CAAQ,CAAC,IAC3C;AAAA,QAAA;AAAA,MAER,OAAO;AACL,cAAM1B,IAAS,MAAM,KAAK,yBAAyBsB,GAAS;AAAA,UAC1D,MAAME;AAAA,UACN,OAAO;AAAA,YACL,OAAO,MAAM,KAAK1E,EAAWuE,CAAgB,CAAC;AAAA,UAAA;AAAA,QAChD,CACD;AACD,QAAKrB,GAAQ,SAGX,KAAK,uBAAuB,IAAIqB,GAAmBrB,EAAO,OAAe,KAAK,IAF9E,KAAK,uBAAuB,IAAIqB,GAAkB,MAAS;AAAA,MAI/D;AAAA,IACF;AACA,WAAO,KAAK,uBAAuB,IAAIA,CAAgB;AAAA,EACzD;AAAA,EAEA,MAAc,oBAAoB;AAChC,QAAI,CAAC,KAAK,gBAAgB;AACxB,YAAMM,IAAY,KAAK,gBAAA,IACnBpE,EAAmB,cAAcE,EAAe,YAAY,CAAC,IAC7D;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA,GAEPuC,IAAS,MAAM,KAAK,yBAAyB,KAAK,aAAa2B,CAAS;AAC9E,UAAI,CAAC3B,GAAQ;AACX,cAAM,IAAI,MAAM,wDAAwD;AAE1E,WAAK,iBAAiB;AAAA,QACpB,IAAIA,EAAO;AAAA,QACX,WAAW7B,EAAmC6B,EAAO,IAAI;AAAA,MAAA;AAAA,IAE7D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,sCAAsC4B,GAAgC;AAE5E,UAAMC,IAAgB,IADMD,EAAmB,CAAC,IACA,GAC1CE,IAAU3E,EAAayE,GAAoBC,CAAa,GACxDE,IAAYF,IAAgB;AAClC,WAAOD,EAAmB,SAASG,GAAWA,IAAYD,CAAO;AAAA,EACnE;AACF;"}
|