@pythnetwork/pyth-sui-js 2.3.0 → 2.4.0
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/cjs/SuiPriceServiceConnection.cjs +29 -0
- package/{lib → dist/cjs}/SuiPriceServiceConnection.d.ts +4 -4
- package/dist/cjs/client.cjs +284 -0
- package/{lib → dist/cjs}/client.d.ts +15 -16
- package/dist/cjs/index.cjs +20 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/SuiPriceServiceConnection.d.ts +14 -0
- package/dist/esm/SuiPriceServiceConnection.mjs +19 -0
- package/dist/esm/client.d.ts +83 -0
- package/{lib/client.js → dist/esm/client.mjs} +105 -109
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/package.json +1 -0
- package/package.json +49 -10
- package/lib/SuiPriceServiceConnection.d.ts.map +0 -1
- package/lib/SuiPriceServiceConnection.js +0 -24
- package/lib/client.d.ts.map +0 -1
- package/lib/examples/SuiRelay.d.ts +0 -3
- package/lib/examples/SuiRelay.d.ts.map +0 -1
- package/lib/examples/SuiRelay.js +0 -98
- package/lib/index.d.ts +0 -4
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -7
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "SuiPriceServiceConnection", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return SuiPriceServiceConnection;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _nodebuffer = require("node:buffer");
|
|
12
|
+
const _hermesclient = require("@pythnetwork/hermes-client");
|
|
13
|
+
class SuiPriceServiceConnection extends _hermesclient.HermesClient {
|
|
14
|
+
/**
|
|
15
|
+
* Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
|
|
16
|
+
* can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
|
|
17
|
+
* the price service returns a non-ok response (e.g: Invalid price ids)
|
|
18
|
+
*
|
|
19
|
+
* @param priceIds - Array of hex-encoded price ids.
|
|
20
|
+
* @returns Array of buffers containing the price update data.
|
|
21
|
+
*/ async getPriceFeedsUpdateData(priceIds) {
|
|
22
|
+
// Fetch the latest price feed update VAAs from the price service
|
|
23
|
+
const updateData = await this.getLatestPriceUpdates(priceIds, {
|
|
24
|
+
encoding: "base64",
|
|
25
|
+
parsed: false
|
|
26
|
+
});
|
|
27
|
+
return updateData.binary.data.map((update)=>_nodebuffer.Buffer.from(update, "base64"));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import type { HexString } from "@pythnetwork/hermes-client";
|
|
3
|
+
import { HermesClient } from "@pythnetwork/hermes-client";
|
|
3
4
|
export declare class SuiPriceServiceConnection extends HermesClient {
|
|
4
5
|
/**
|
|
5
6
|
* Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
|
|
6
7
|
* can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
|
|
7
8
|
* the price service returns a non-ok response (e.g: Invalid price ids)
|
|
8
9
|
*
|
|
9
|
-
* @param priceIds Array of hex-encoded price ids.
|
|
10
|
+
* @param priceIds - Array of hex-encoded price ids.
|
|
10
11
|
* @returns Array of buffers containing the price update data.
|
|
11
12
|
*/
|
|
12
13
|
getPriceFeedsUpdateData(priceIds: HexString[]): Promise<Buffer[]>;
|
|
13
14
|
}
|
|
14
|
-
//# sourceMappingURL=SuiPriceServiceConnection.d.ts.map
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable no-console */ "use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "SuiPythClient", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return SuiPythClient;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _nodebuffer = require("node:buffer");
|
|
12
|
+
const _bcs = require("@mysten/sui/bcs");
|
|
13
|
+
const _utils = require("@mysten/sui/utils");
|
|
14
|
+
const MAX_ARGUMENT_SIZE = 16 * 1024;
|
|
15
|
+
class SuiPythClient {
|
|
16
|
+
provider;
|
|
17
|
+
pythStateId;
|
|
18
|
+
wormholeStateId;
|
|
19
|
+
pythPackageId;
|
|
20
|
+
wormholePackageId;
|
|
21
|
+
priceTableInfo;
|
|
22
|
+
priceFeedObjectIdCache = new Map();
|
|
23
|
+
baseUpdateFee;
|
|
24
|
+
constructor(provider, pythStateId, wormholeStateId){
|
|
25
|
+
this.provider = provider;
|
|
26
|
+
this.pythStateId = pythStateId;
|
|
27
|
+
this.wormholeStateId = wormholeStateId;
|
|
28
|
+
this.pythPackageId = undefined;
|
|
29
|
+
this.wormholePackageId = undefined;
|
|
30
|
+
}
|
|
31
|
+
async getBaseUpdateFee() {
|
|
32
|
+
if (this.baseUpdateFee === undefined) {
|
|
33
|
+
const result = await this.provider.getObject({
|
|
34
|
+
id: this.pythStateId,
|
|
35
|
+
options: {
|
|
36
|
+
showContent: true
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
if (!result.data?.content || result.data.content.dataType !== "moveObject") throw new Error("Unable to fetch pyth state object");
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
this.baseUpdateFee = result.data.content.fields.base_update_fee;
|
|
43
|
+
}
|
|
44
|
+
return this.baseUpdateFee;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* getPackageId returns the latest package id that the object belongs to. Use this to
|
|
48
|
+
* fetch the latest package id for a given object id and handle package upgrades automatically.
|
|
49
|
+
* @param objectId - the object id
|
|
50
|
+
* @returns package id
|
|
51
|
+
*/ async getPackageId(objectId) {
|
|
52
|
+
const state = await this.provider.getObject({
|
|
53
|
+
id: objectId,
|
|
54
|
+
options: {
|
|
55
|
+
showContent: true
|
|
56
|
+
}
|
|
57
|
+
}).then((result)=>{
|
|
58
|
+
if (result.data?.content?.dataType == "moveObject") {
|
|
59
|
+
return result.data.content.fields;
|
|
60
|
+
}
|
|
61
|
+
console.log(result.data?.content);
|
|
62
|
+
throw new Error(`Cannot fetch package id for object ${objectId}`);
|
|
63
|
+
});
|
|
64
|
+
if ("upgrade_cap" in state) {
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
|
|
68
|
+
return state.upgrade_cap.fields.package;
|
|
69
|
+
}
|
|
70
|
+
throw new Error("upgrade_cap not found");
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
|
|
74
|
+
* @param vaas - array of vaas to verify
|
|
75
|
+
* @param tx - transaction block to add commands to
|
|
76
|
+
*/ async verifyVaas(vaas, tx) {
|
|
77
|
+
const wormholePackageId = await this.getWormholePackageId();
|
|
78
|
+
const verifiedVaas = [];
|
|
79
|
+
for (const vaa of vaas){
|
|
80
|
+
const [verifiedVaa] = tx.moveCall({
|
|
81
|
+
target: `${wormholePackageId}::vaa::parse_and_verify`,
|
|
82
|
+
arguments: [
|
|
83
|
+
tx.object(this.wormholeStateId),
|
|
84
|
+
tx.pure(_bcs.bcs.vector(_bcs.bcs.U8).serialize([
|
|
85
|
+
...vaa
|
|
86
|
+
], {
|
|
87
|
+
maxSize: MAX_ARGUMENT_SIZE
|
|
88
|
+
}).toBytes()),
|
|
89
|
+
tx.object(_utils.SUI_CLOCK_OBJECT_ID)
|
|
90
|
+
]
|
|
91
|
+
});
|
|
92
|
+
verifiedVaas.push(verifiedVaa);
|
|
93
|
+
}
|
|
94
|
+
return verifiedVaas;
|
|
95
|
+
}
|
|
96
|
+
async verifyVaasAndGetHotPotato(tx, updates, packageId) {
|
|
97
|
+
if (updates.length > 1) {
|
|
98
|
+
throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
|
|
99
|
+
}
|
|
100
|
+
const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
|
|
101
|
+
const verifiedVaas = await this.verifyVaas([
|
|
102
|
+
vaa
|
|
103
|
+
], tx);
|
|
104
|
+
const [priceUpdatesHotPotato] = tx.moveCall({
|
|
105
|
+
target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,
|
|
106
|
+
arguments: [
|
|
107
|
+
tx.object(this.pythStateId),
|
|
108
|
+
tx.pure(_bcs.bcs.vector(_bcs.bcs.U8).serialize([
|
|
109
|
+
...updates[0]
|
|
110
|
+
], {
|
|
111
|
+
maxSize: MAX_ARGUMENT_SIZE
|
|
112
|
+
}).toBytes()),
|
|
113
|
+
verifiedVaas[0],
|
|
114
|
+
tx.object(_utils.SUI_CLOCK_OBJECT_ID)
|
|
115
|
+
]
|
|
116
|
+
});
|
|
117
|
+
return priceUpdatesHotPotato;
|
|
118
|
+
}
|
|
119
|
+
async executePriceFeedUpdates(tx, packageId, feedIds, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
120
|
+
priceUpdatesHotPotato, coins) {
|
|
121
|
+
const priceInfoObjects = [];
|
|
122
|
+
let coinId = 0;
|
|
123
|
+
for (const feedId of feedIds){
|
|
124
|
+
const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
|
|
125
|
+
if (!priceInfoObjectId) {
|
|
126
|
+
throw new Error(`Price feed ${feedId} not found, please create it first`);
|
|
127
|
+
}
|
|
128
|
+
priceInfoObjects.push(priceInfoObjectId);
|
|
129
|
+
[priceUpdatesHotPotato] = tx.moveCall({
|
|
130
|
+
target: `${packageId}::pyth::update_single_price_feed`,
|
|
131
|
+
arguments: [
|
|
132
|
+
tx.object(this.pythStateId),
|
|
133
|
+
priceUpdatesHotPotato,
|
|
134
|
+
tx.object(priceInfoObjectId),
|
|
135
|
+
coins[coinId],
|
|
136
|
+
tx.object(_utils.SUI_CLOCK_OBJECT_ID)
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
coinId++;
|
|
140
|
+
}
|
|
141
|
+
tx.moveCall({
|
|
142
|
+
target: `${packageId}::hot_potato_vector::destroy`,
|
|
143
|
+
arguments: [
|
|
144
|
+
priceUpdatesHotPotato
|
|
145
|
+
],
|
|
146
|
+
typeArguments: [
|
|
147
|
+
`${packageId}::price_info::PriceInfo`
|
|
148
|
+
]
|
|
149
|
+
});
|
|
150
|
+
return priceInfoObjects;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Adds the necessary commands for updating the pyth price feeds to the transaction block.
|
|
154
|
+
* @param tx - transaction block to add commands to
|
|
155
|
+
* @param updates - array of price feed updates received from the price service
|
|
156
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
157
|
+
*/ async updatePriceFeeds(tx, updates, feedIds) {
|
|
158
|
+
const packageId = await this.getPythPackageId();
|
|
159
|
+
const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
|
|
160
|
+
const baseUpdateFee = await this.getBaseUpdateFee();
|
|
161
|
+
const coins = tx.splitCoins(tx.gas, feedIds.map(()=>tx.pure.u64(baseUpdateFee)));
|
|
162
|
+
return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
|
|
166
|
+
* @param tx - transaction block to add commands to
|
|
167
|
+
* @param updates - array of price feed updates received from the price service
|
|
168
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
169
|
+
* @param coins - array of Coins for payment of update operations
|
|
170
|
+
*/ async updatePriceFeedsWithCoins(tx, updates, feedIds, coins) {
|
|
171
|
+
const packageId = await this.getPythPackageId();
|
|
172
|
+
const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
|
|
173
|
+
return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
|
|
174
|
+
}
|
|
175
|
+
async createPriceFeed(tx, updates) {
|
|
176
|
+
const packageId = await this.getPythPackageId();
|
|
177
|
+
if (updates.length > 1) {
|
|
178
|
+
throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
|
|
179
|
+
}
|
|
180
|
+
const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
|
|
181
|
+
const verifiedVaas = await this.verifyVaas([
|
|
182
|
+
vaa
|
|
183
|
+
], tx);
|
|
184
|
+
tx.moveCall({
|
|
185
|
+
target: `${packageId}::pyth::create_price_feeds_using_accumulator`,
|
|
186
|
+
arguments: [
|
|
187
|
+
tx.object(this.pythStateId),
|
|
188
|
+
tx.pure(_bcs.bcs.vector(_bcs.bcs.U8).serialize([
|
|
189
|
+
...updates[0]
|
|
190
|
+
], {
|
|
191
|
+
maxSize: MAX_ARGUMENT_SIZE
|
|
192
|
+
}).toBytes()),
|
|
193
|
+
verifiedVaas[0],
|
|
194
|
+
tx.object(_utils.SUI_CLOCK_OBJECT_ID)
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get the packageId for the wormhole package if not already cached
|
|
200
|
+
*/ async getWormholePackageId() {
|
|
201
|
+
if (!this.wormholePackageId) {
|
|
202
|
+
this.wormholePackageId = await this.getPackageId(this.wormholeStateId);
|
|
203
|
+
}
|
|
204
|
+
return this.wormholePackageId;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get the packageId for the pyth package if not already cached
|
|
208
|
+
*/ async getPythPackageId() {
|
|
209
|
+
if (!this.pythPackageId) {
|
|
210
|
+
this.pythPackageId = await this.getPackageId(this.pythStateId);
|
|
211
|
+
}
|
|
212
|
+
return this.pythPackageId;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get the priceFeedObjectId for a given feedId if not already cached
|
|
216
|
+
* @param feedId - the feed id
|
|
217
|
+
*/ async getPriceFeedObjectId(feedId) {
|
|
218
|
+
const normalizedFeedId = feedId.replace("0x", "");
|
|
219
|
+
if (!this.priceFeedObjectIdCache.has(normalizedFeedId)) {
|
|
220
|
+
const { id: tableId, fieldType } = await this.getPriceTableInfo();
|
|
221
|
+
const result = await this.provider.getDynamicFieldObject({
|
|
222
|
+
parentId: tableId,
|
|
223
|
+
name: {
|
|
224
|
+
type: `${fieldType}::price_identifier::PriceIdentifier`,
|
|
225
|
+
value: {
|
|
226
|
+
bytes: [
|
|
227
|
+
..._nodebuffer.Buffer.from(normalizedFeedId, "hex")
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
if (!result.data?.content) {
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
if (result.data.content.dataType !== "moveObject") {
|
|
236
|
+
throw new Error("Price feed type mismatch");
|
|
237
|
+
}
|
|
238
|
+
this.priceFeedObjectIdCache.set(normalizedFeedId, // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
239
|
+
// @ts-ignore
|
|
240
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
241
|
+
result.data.content.fields.value);
|
|
242
|
+
}
|
|
243
|
+
return this.priceFeedObjectIdCache.get(normalizedFeedId);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Fetches the price table object id for the current state id if not cached
|
|
247
|
+
* @returns price table object id
|
|
248
|
+
*/ async getPriceTableInfo() {
|
|
249
|
+
if (this.priceTableInfo === undefined) {
|
|
250
|
+
const result = await this.provider.getDynamicFieldObject({
|
|
251
|
+
parentId: this.pythStateId,
|
|
252
|
+
name: {
|
|
253
|
+
type: "vector<u8>",
|
|
254
|
+
value: "price_info"
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
if (!result.data?.type) {
|
|
258
|
+
throw new Error("Price Table not found, contract may not be initialized");
|
|
259
|
+
}
|
|
260
|
+
let type = result.data.type.replace("0x2::table::Table<", "");
|
|
261
|
+
type = type.replace("::price_identifier::PriceIdentifier, 0x2::object::ID>", "");
|
|
262
|
+
this.priceTableInfo = {
|
|
263
|
+
id: result.data.objectId,
|
|
264
|
+
fieldType: type
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return this.priceTableInfo;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Obtains the vaa bytes embedded in an accumulator message.
|
|
271
|
+
* @param accumulatorMessage - the accumulator price update message
|
|
272
|
+
* @returns vaa bytes as a uint8 array
|
|
273
|
+
*/ extractVaaBytesFromAccumulatorMessage(accumulatorMessage) {
|
|
274
|
+
// the first 6 bytes in the accumulator message encode the header, major, and minor bytes
|
|
275
|
+
// we ignore them, since we are only interested in the VAA bytes
|
|
276
|
+
const trailingPayloadSize = accumulatorMessage.readUint8(6);
|
|
277
|
+
const vaaSizeOffset = 7 + // header bytes (header(4) + major(1) + minor(1) + trailing payload size(1))
|
|
278
|
+
trailingPayloadSize + // trailing payload (variable number of bytes)
|
|
279
|
+
1; // proof_type (1 byte)
|
|
280
|
+
const vaaSize = accumulatorMessage.readUint16BE(vaaSizeOffset);
|
|
281
|
+
const vaaOffset = vaaSizeOffset + 2;
|
|
282
|
+
return accumulatorMessage.subarray(vaaOffset, vaaOffset + vaaSize);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
1
2
|
import { SuiClient } from "@mysten/sui/client";
|
|
2
3
|
import { Transaction } from "@mysten/sui/transactions";
|
|
3
|
-
import { HexString } from "@pythnetwork/hermes-client";
|
|
4
|
-
import { Buffer } from "buffer";
|
|
4
|
+
import type { HexString } from "@pythnetwork/hermes-client";
|
|
5
5
|
type NestedTransactionResult = {
|
|
6
6
|
$kind: "NestedResult";
|
|
7
7
|
NestedResult: [number, number];
|
|
@@ -21,34 +21,34 @@ export declare class SuiPythClient {
|
|
|
21
21
|
/**
|
|
22
22
|
* getPackageId returns the latest package id that the object belongs to. Use this to
|
|
23
23
|
* fetch the latest package id for a given object id and handle package upgrades automatically.
|
|
24
|
-
* @param objectId
|
|
24
|
+
* @param objectId - the object id
|
|
25
25
|
* @returns package id
|
|
26
26
|
*/
|
|
27
27
|
getPackageId(objectId: ObjectId): Promise<ObjectId>;
|
|
28
28
|
/**
|
|
29
29
|
* Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
|
|
30
|
-
* @param vaas array of vaas to verify
|
|
31
|
-
* @param tx transaction block to add commands to
|
|
30
|
+
* @param vaas - array of vaas to verify
|
|
31
|
+
* @param tx - transaction block to add commands to
|
|
32
32
|
*/
|
|
33
|
-
verifyVaas(vaas: Buffer[], tx: Transaction): Promise<{
|
|
33
|
+
verifyVaas(vaas: Buffer[], tx: Transaction): Promise<({
|
|
34
34
|
$kind: "NestedResult";
|
|
35
35
|
NestedResult: [number, number];
|
|
36
|
-
}[]>;
|
|
36
|
+
} | undefined)[]>;
|
|
37
37
|
verifyVaasAndGetHotPotato(tx: Transaction, updates: Buffer[], packageId: string): Promise<NestedTransactionResult>;
|
|
38
38
|
executePriceFeedUpdates(tx: Transaction, packageId: string, feedIds: HexString[], priceUpdatesHotPotato: any, coins: NestedTransactionResult[]): Promise<string[]>;
|
|
39
39
|
/**
|
|
40
40
|
* Adds the necessary commands for updating the pyth price feeds to the transaction block.
|
|
41
|
-
* @param tx transaction block to add commands to
|
|
42
|
-
* @param updates array of price feed updates received from the price service
|
|
43
|
-
* @param feedIds array of feed ids to update (in hex format)
|
|
41
|
+
* @param tx - transaction block to add commands to
|
|
42
|
+
* @param updates - array of price feed updates received from the price service
|
|
43
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
44
44
|
*/
|
|
45
45
|
updatePriceFeeds(tx: Transaction, updates: Buffer[], feedIds: HexString[]): Promise<ObjectId[]>;
|
|
46
46
|
/**
|
|
47
47
|
* Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
|
|
48
|
-
* @param tx transaction block to add commands to
|
|
49
|
-
* @param updates array of price feed updates received from the price service
|
|
50
|
-
* @param feedIds array of feed ids to update (in hex format)
|
|
51
|
-
* @param coins array of Coins for payment of update operations
|
|
48
|
+
* @param tx - transaction block to add commands to
|
|
49
|
+
* @param updates - array of price feed updates received from the price service
|
|
50
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
51
|
+
* @param coins - array of Coins for payment of update operations
|
|
52
52
|
*/
|
|
53
53
|
updatePriceFeedsWithCoins(tx: Transaction, updates: Buffer[], feedIds: HexString[], coins: NestedTransactionResult[]): Promise<ObjectId[]>;
|
|
54
54
|
createPriceFeed(tx: Transaction, updates: Buffer[]): Promise<void>;
|
|
@@ -62,7 +62,7 @@ export declare class SuiPythClient {
|
|
|
62
62
|
getPythPackageId(): Promise<string>;
|
|
63
63
|
/**
|
|
64
64
|
* Get the priceFeedObjectId for a given feedId if not already cached
|
|
65
|
-
* @param feedId
|
|
65
|
+
* @param feedId - the feed id
|
|
66
66
|
*/
|
|
67
67
|
getPriceFeedObjectId(feedId: HexString): Promise<ObjectId | undefined>;
|
|
68
68
|
/**
|
|
@@ -81,4 +81,3 @@ export declare class SuiPythClient {
|
|
|
81
81
|
extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Buffer): Buffer;
|
|
82
82
|
}
|
|
83
83
|
export {};
|
|
84
|
-
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get SuiPriceServiceConnection () {
|
|
13
|
+
return _SuiPriceServiceConnection.SuiPriceServiceConnection;
|
|
14
|
+
},
|
|
15
|
+
get SuiPythClient () {
|
|
16
|
+
return _client.SuiPythClient;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _SuiPriceServiceConnection = require("./SuiPriceServiceConnection.cjs");
|
|
20
|
+
const _client = require("./client.cjs");
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { SuiPriceServiceConnection } from "./SuiPriceServiceConnection.js";
|
|
2
|
+
export { SuiPythClient } from "./client.js";
|
|
3
|
+
export type { AssetType, BinaryPriceUpdate, DurationInMs, DurationInSeconds, EncodingType, HermesClientConfig, HexString, PriceFeedMetadata, PriceIdInput, PriceUpdate, PublisherCaps, TwapsResponse, UnixTimestamp, } from "@pythnetwork/hermes-client";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "commonjs" }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import type { HexString } from "@pythnetwork/hermes-client";
|
|
3
|
+
import { HermesClient } from "@pythnetwork/hermes-client";
|
|
4
|
+
export declare class SuiPriceServiceConnection extends HermesClient {
|
|
5
|
+
/**
|
|
6
|
+
* Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
|
|
7
|
+
* can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
|
|
8
|
+
* the price service returns a non-ok response (e.g: Invalid price ids)
|
|
9
|
+
*
|
|
10
|
+
* @param priceIds - Array of hex-encoded price ids.
|
|
11
|
+
* @returns Array of buffers containing the price update data.
|
|
12
|
+
*/
|
|
13
|
+
getPriceFeedsUpdateData(priceIds: HexString[]): Promise<Buffer[]>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { HermesClient } from "@pythnetwork/hermes-client";
|
|
3
|
+
export class SuiPriceServiceConnection extends HermesClient {
|
|
4
|
+
/**
|
|
5
|
+
* Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
|
|
6
|
+
* can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
|
|
7
|
+
* the price service returns a non-ok response (e.g: Invalid price ids)
|
|
8
|
+
*
|
|
9
|
+
* @param priceIds - Array of hex-encoded price ids.
|
|
10
|
+
* @returns Array of buffers containing the price update data.
|
|
11
|
+
*/ async getPriceFeedsUpdateData(priceIds) {
|
|
12
|
+
// Fetch the latest price feed update VAAs from the price service
|
|
13
|
+
const updateData = await this.getLatestPriceUpdates(priceIds, {
|
|
14
|
+
encoding: "base64",
|
|
15
|
+
parsed: false
|
|
16
|
+
});
|
|
17
|
+
return updateData.binary.data.map((update)=>Buffer.from(update, "base64"));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { SuiClient } from "@mysten/sui/client";
|
|
3
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
4
|
+
import type { HexString } from "@pythnetwork/hermes-client";
|
|
5
|
+
type NestedTransactionResult = {
|
|
6
|
+
$kind: "NestedResult";
|
|
7
|
+
NestedResult: [number, number];
|
|
8
|
+
};
|
|
9
|
+
export type ObjectId = string;
|
|
10
|
+
export declare class SuiPythClient {
|
|
11
|
+
provider: SuiClient;
|
|
12
|
+
pythStateId: ObjectId;
|
|
13
|
+
wormholeStateId: ObjectId;
|
|
14
|
+
private pythPackageId;
|
|
15
|
+
private wormholePackageId;
|
|
16
|
+
private priceTableInfo;
|
|
17
|
+
private priceFeedObjectIdCache;
|
|
18
|
+
private baseUpdateFee;
|
|
19
|
+
constructor(provider: SuiClient, pythStateId: ObjectId, wormholeStateId: ObjectId);
|
|
20
|
+
getBaseUpdateFee(): Promise<number>;
|
|
21
|
+
/**
|
|
22
|
+
* getPackageId returns the latest package id that the object belongs to. Use this to
|
|
23
|
+
* fetch the latest package id for a given object id and handle package upgrades automatically.
|
|
24
|
+
* @param objectId - the object id
|
|
25
|
+
* @returns package id
|
|
26
|
+
*/
|
|
27
|
+
getPackageId(objectId: ObjectId): Promise<ObjectId>;
|
|
28
|
+
/**
|
|
29
|
+
* Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
|
|
30
|
+
* @param vaas - array of vaas to verify
|
|
31
|
+
* @param tx - transaction block to add commands to
|
|
32
|
+
*/
|
|
33
|
+
verifyVaas(vaas: Buffer[], tx: Transaction): Promise<({
|
|
34
|
+
$kind: "NestedResult";
|
|
35
|
+
NestedResult: [number, number];
|
|
36
|
+
} | undefined)[]>;
|
|
37
|
+
verifyVaasAndGetHotPotato(tx: Transaction, updates: Buffer[], packageId: string): Promise<NestedTransactionResult>;
|
|
38
|
+
executePriceFeedUpdates(tx: Transaction, packageId: string, feedIds: HexString[], priceUpdatesHotPotato: any, coins: NestedTransactionResult[]): Promise<string[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Adds the necessary commands for updating the pyth price feeds to the transaction block.
|
|
41
|
+
* @param tx - transaction block to add commands to
|
|
42
|
+
* @param updates - array of price feed updates received from the price service
|
|
43
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
44
|
+
*/
|
|
45
|
+
updatePriceFeeds(tx: Transaction, updates: Buffer[], feedIds: HexString[]): Promise<ObjectId[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
|
|
48
|
+
* @param tx - transaction block to add commands to
|
|
49
|
+
* @param updates - array of price feed updates received from the price service
|
|
50
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
51
|
+
* @param coins - array of Coins for payment of update operations
|
|
52
|
+
*/
|
|
53
|
+
updatePriceFeedsWithCoins(tx: Transaction, updates: Buffer[], feedIds: HexString[], coins: NestedTransactionResult[]): Promise<ObjectId[]>;
|
|
54
|
+
createPriceFeed(tx: Transaction, updates: Buffer[]): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Get the packageId for the wormhole package if not already cached
|
|
57
|
+
*/
|
|
58
|
+
getWormholePackageId(): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Get the packageId for the pyth package if not already cached
|
|
61
|
+
*/
|
|
62
|
+
getPythPackageId(): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Get the priceFeedObjectId for a given feedId if not already cached
|
|
65
|
+
* @param feedId - the feed id
|
|
66
|
+
*/
|
|
67
|
+
getPriceFeedObjectId(feedId: HexString): Promise<ObjectId | undefined>;
|
|
68
|
+
/**
|
|
69
|
+
* Fetches the price table object id for the current state id if not cached
|
|
70
|
+
* @returns price table object id
|
|
71
|
+
*/
|
|
72
|
+
getPriceTableInfo(): Promise<{
|
|
73
|
+
id: ObjectId;
|
|
74
|
+
fieldType: ObjectId;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Obtains the vaa bytes embedded in an accumulator message.
|
|
78
|
+
* @param accumulatorMessage - the accumulator price update message
|
|
79
|
+
* @returns vaa bytes as a uint8 array
|
|
80
|
+
*/
|
|
81
|
+
extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Buffer): Buffer;
|
|
82
|
+
}
|
|
83
|
+
export {};
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const utils_1 = require("@mysten/sui/utils");
|
|
5
|
-
const bcs_1 = require("@mysten/sui/bcs");
|
|
6
|
-
const buffer_1 = require("buffer");
|
|
1
|
+
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable no-console */ import { Buffer } from "node:buffer";
|
|
2
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
3
|
+
import { SUI_CLOCK_OBJECT_ID } from "@mysten/sui/utils";
|
|
7
4
|
const MAX_ARGUMENT_SIZE = 16 * 1024;
|
|
8
|
-
class SuiPythClient {
|
|
5
|
+
export class SuiPythClient {
|
|
9
6
|
provider;
|
|
10
7
|
pythStateId;
|
|
11
8
|
wormholeStateId;
|
|
@@ -14,7 +11,7 @@ class SuiPythClient {
|
|
|
14
11
|
priceTableInfo;
|
|
15
12
|
priceFeedObjectIdCache = new Map();
|
|
16
13
|
baseUpdateFee;
|
|
17
|
-
constructor(provider, pythStateId, wormholeStateId)
|
|
14
|
+
constructor(provider, pythStateId, wormholeStateId){
|
|
18
15
|
this.provider = provider;
|
|
19
16
|
this.pythStateId = pythStateId;
|
|
20
17
|
this.wormholeStateId = wormholeStateId;
|
|
@@ -25,12 +22,11 @@ class SuiPythClient {
|
|
|
25
22
|
if (this.baseUpdateFee === undefined) {
|
|
26
23
|
const result = await this.provider.getObject({
|
|
27
24
|
id: this.pythStateId,
|
|
28
|
-
options: {
|
|
25
|
+
options: {
|
|
26
|
+
showContent: true
|
|
27
|
+
}
|
|
29
28
|
});
|
|
30
|
-
if (!result.data ||
|
|
31
|
-
!result.data.content ||
|
|
32
|
-
result.data.content.dataType !== "moveObject")
|
|
33
|
-
throw new Error("Unable to fetch pyth state object");
|
|
29
|
+
if (!result.data?.content || result.data.content.dataType !== "moveObject") throw new Error("Unable to fetch pyth state object");
|
|
34
30
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
35
31
|
// @ts-ignore
|
|
36
32
|
this.baseUpdateFee = result.data.content.fields.base_update_fee;
|
|
@@ -38,20 +34,17 @@ class SuiPythClient {
|
|
|
38
34
|
return this.baseUpdateFee;
|
|
39
35
|
}
|
|
40
36
|
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const state = await this.provider
|
|
48
|
-
.getObject({
|
|
37
|
+
* getPackageId returns the latest package id that the object belongs to. Use this to
|
|
38
|
+
* fetch the latest package id for a given object id and handle package upgrades automatically.
|
|
39
|
+
* @param objectId - the object id
|
|
40
|
+
* @returns package id
|
|
41
|
+
*/ async getPackageId(objectId) {
|
|
42
|
+
const state = await this.provider.getObject({
|
|
49
43
|
id: objectId,
|
|
50
44
|
options: {
|
|
51
|
-
showContent: true
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
.then((result) => {
|
|
45
|
+
showContent: true
|
|
46
|
+
}
|
|
47
|
+
}).then((result)=>{
|
|
55
48
|
if (result.data?.content?.dataType == "moveObject") {
|
|
56
49
|
return result.data.content.fields;
|
|
57
50
|
}
|
|
@@ -61,31 +54,30 @@ class SuiPythClient {
|
|
|
61
54
|
if ("upgrade_cap" in state) {
|
|
62
55
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
63
56
|
// @ts-ignore
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
|
|
64
58
|
return state.upgrade_cap.fields.package;
|
|
65
59
|
}
|
|
66
60
|
throw new Error("upgrade_cap not found");
|
|
67
61
|
}
|
|
68
62
|
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
async verifyVaas(vaas, tx) {
|
|
63
|
+
* Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
|
|
64
|
+
* @param vaas - array of vaas to verify
|
|
65
|
+
* @param tx - transaction block to add commands to
|
|
66
|
+
*/ async verifyVaas(vaas, tx) {
|
|
74
67
|
const wormholePackageId = await this.getWormholePackageId();
|
|
75
68
|
const verifiedVaas = [];
|
|
76
|
-
for (const vaa of vaas)
|
|
69
|
+
for (const vaa of vaas){
|
|
77
70
|
const [verifiedVaa] = tx.moveCall({
|
|
78
71
|
target: `${wormholePackageId}::vaa::parse_and_verify`,
|
|
79
72
|
arguments: [
|
|
80
73
|
tx.object(this.wormholeStateId),
|
|
81
|
-
tx.pure(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
maxSize: MAX_ARGUMENT_SIZE
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
],
|
|
74
|
+
tx.pure(bcs.vector(bcs.U8).serialize([
|
|
75
|
+
...vaa
|
|
76
|
+
], {
|
|
77
|
+
maxSize: MAX_ARGUMENT_SIZE
|
|
78
|
+
}).toBytes()),
|
|
79
|
+
tx.object(SUI_CLOCK_OBJECT_ID)
|
|
80
|
+
]
|
|
89
81
|
});
|
|
90
82
|
verifiedVaas.push(verifiedVaa);
|
|
91
83
|
}
|
|
@@ -96,27 +88,29 @@ class SuiPythClient {
|
|
|
96
88
|
throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
|
|
97
89
|
}
|
|
98
90
|
const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
|
|
99
|
-
const verifiedVaas = await this.verifyVaas([
|
|
91
|
+
const verifiedVaas = await this.verifyVaas([
|
|
92
|
+
vaa
|
|
93
|
+
], tx);
|
|
100
94
|
const [priceUpdatesHotPotato] = tx.moveCall({
|
|
101
95
|
target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,
|
|
102
96
|
arguments: [
|
|
103
97
|
tx.object(this.pythStateId),
|
|
104
|
-
tx.pure(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
maxSize: MAX_ARGUMENT_SIZE
|
|
108
|
-
})
|
|
109
|
-
.toBytes()),
|
|
98
|
+
tx.pure(bcs.vector(bcs.U8).serialize([
|
|
99
|
+
...updates[0]
|
|
100
|
+
], {
|
|
101
|
+
maxSize: MAX_ARGUMENT_SIZE
|
|
102
|
+
}).toBytes()),
|
|
110
103
|
verifiedVaas[0],
|
|
111
|
-
tx.object(
|
|
112
|
-
]
|
|
104
|
+
tx.object(SUI_CLOCK_OBJECT_ID)
|
|
105
|
+
]
|
|
113
106
|
});
|
|
114
107
|
return priceUpdatesHotPotato;
|
|
115
108
|
}
|
|
116
|
-
async executePriceFeedUpdates(tx, packageId, feedIds,
|
|
109
|
+
async executePriceFeedUpdates(tx, packageId, feedIds, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
110
|
+
priceUpdatesHotPotato, coins) {
|
|
117
111
|
const priceInfoObjects = [];
|
|
118
112
|
let coinId = 0;
|
|
119
|
-
for (const feedId of feedIds)
|
|
113
|
+
for (const feedId of feedIds){
|
|
120
114
|
const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
|
|
121
115
|
if (!priceInfoObjectId) {
|
|
122
116
|
throw new Error(`Price feed ${feedId} not found, please create it first`);
|
|
@@ -129,39 +123,41 @@ class SuiPythClient {
|
|
|
129
123
|
priceUpdatesHotPotato,
|
|
130
124
|
tx.object(priceInfoObjectId),
|
|
131
125
|
coins[coinId],
|
|
132
|
-
tx.object(
|
|
133
|
-
]
|
|
126
|
+
tx.object(SUI_CLOCK_OBJECT_ID)
|
|
127
|
+
]
|
|
134
128
|
});
|
|
135
129
|
coinId++;
|
|
136
130
|
}
|
|
137
131
|
tx.moveCall({
|
|
138
132
|
target: `${packageId}::hot_potato_vector::destroy`,
|
|
139
|
-
arguments: [
|
|
140
|
-
|
|
133
|
+
arguments: [
|
|
134
|
+
priceUpdatesHotPotato
|
|
135
|
+
],
|
|
136
|
+
typeArguments: [
|
|
137
|
+
`${packageId}::price_info::PriceInfo`
|
|
138
|
+
]
|
|
141
139
|
});
|
|
142
140
|
return priceInfoObjects;
|
|
143
141
|
}
|
|
144
142
|
/**
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
async updatePriceFeeds(tx, updates, feedIds) {
|
|
143
|
+
* Adds the necessary commands for updating the pyth price feeds to the transaction block.
|
|
144
|
+
* @param tx - transaction block to add commands to
|
|
145
|
+
* @param updates - array of price feed updates received from the price service
|
|
146
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
147
|
+
*/ async updatePriceFeeds(tx, updates, feedIds) {
|
|
151
148
|
const packageId = await this.getPythPackageId();
|
|
152
149
|
const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
|
|
153
150
|
const baseUpdateFee = await this.getBaseUpdateFee();
|
|
154
|
-
const coins = tx.splitCoins(tx.gas, feedIds.map(()
|
|
151
|
+
const coins = tx.splitCoins(tx.gas, feedIds.map(()=>tx.pure.u64(baseUpdateFee)));
|
|
155
152
|
return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
|
|
156
153
|
}
|
|
157
154
|
/**
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
async updatePriceFeedsWithCoins(tx, updates, feedIds, coins) {
|
|
155
|
+
* Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
|
|
156
|
+
* @param tx - transaction block to add commands to
|
|
157
|
+
* @param updates - array of price feed updates received from the price service
|
|
158
|
+
* @param feedIds - array of feed ids to update (in hex format)
|
|
159
|
+
* @param coins - array of Coins for payment of update operations
|
|
160
|
+
*/ async updatePriceFeedsWithCoins(tx, updates, feedIds, coins) {
|
|
165
161
|
const packageId = await this.getPythPackageId();
|
|
166
162
|
const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
|
|
167
163
|
return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
|
|
@@ -172,45 +168,43 @@ class SuiPythClient {
|
|
|
172
168
|
throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
|
|
173
169
|
}
|
|
174
170
|
const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
|
|
175
|
-
const verifiedVaas = await this.verifyVaas([
|
|
171
|
+
const verifiedVaas = await this.verifyVaas([
|
|
172
|
+
vaa
|
|
173
|
+
], tx);
|
|
176
174
|
tx.moveCall({
|
|
177
175
|
target: `${packageId}::pyth::create_price_feeds_using_accumulator`,
|
|
178
176
|
arguments: [
|
|
179
177
|
tx.object(this.pythStateId),
|
|
180
|
-
tx.pure(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
maxSize: MAX_ARGUMENT_SIZE
|
|
184
|
-
})
|
|
185
|
-
.toBytes()),
|
|
178
|
+
tx.pure(bcs.vector(bcs.U8).serialize([
|
|
179
|
+
...updates[0]
|
|
180
|
+
], {
|
|
181
|
+
maxSize: MAX_ARGUMENT_SIZE
|
|
182
|
+
}).toBytes()),
|
|
186
183
|
verifiedVaas[0],
|
|
187
|
-
tx.object(
|
|
188
|
-
]
|
|
184
|
+
tx.object(SUI_CLOCK_OBJECT_ID)
|
|
185
|
+
]
|
|
189
186
|
});
|
|
190
187
|
}
|
|
191
188
|
/**
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
async getWormholePackageId() {
|
|
189
|
+
* Get the packageId for the wormhole package if not already cached
|
|
190
|
+
*/ async getWormholePackageId() {
|
|
195
191
|
if (!this.wormholePackageId) {
|
|
196
192
|
this.wormholePackageId = await this.getPackageId(this.wormholeStateId);
|
|
197
193
|
}
|
|
198
194
|
return this.wormholePackageId;
|
|
199
195
|
}
|
|
200
196
|
/**
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
async getPythPackageId() {
|
|
197
|
+
* Get the packageId for the pyth package if not already cached
|
|
198
|
+
*/ async getPythPackageId() {
|
|
204
199
|
if (!this.pythPackageId) {
|
|
205
200
|
this.pythPackageId = await this.getPackageId(this.pythStateId);
|
|
206
201
|
}
|
|
207
202
|
return this.pythPackageId;
|
|
208
203
|
}
|
|
209
204
|
/**
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
async getPriceFeedObjectId(feedId) {
|
|
205
|
+
* Get the priceFeedObjectId for a given feedId if not already cached
|
|
206
|
+
* @param feedId - the feed id
|
|
207
|
+
*/ async getPriceFeedObjectId(feedId) {
|
|
214
208
|
const normalizedFeedId = feedId.replace("0x", "");
|
|
215
209
|
if (!this.priceFeedObjectIdCache.has(normalizedFeedId)) {
|
|
216
210
|
const { id: tableId, fieldType } = await this.getPriceTableInfo();
|
|
@@ -219,60 +213,62 @@ class SuiPythClient {
|
|
|
219
213
|
name: {
|
|
220
214
|
type: `${fieldType}::price_identifier::PriceIdentifier`,
|
|
221
215
|
value: {
|
|
222
|
-
bytes:
|
|
223
|
-
|
|
224
|
-
|
|
216
|
+
bytes: [
|
|
217
|
+
...Buffer.from(normalizedFeedId, "hex")
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
225
221
|
});
|
|
226
|
-
if (!result.data
|
|
222
|
+
if (!result.data?.content) {
|
|
227
223
|
return undefined;
|
|
228
224
|
}
|
|
229
225
|
if (result.data.content.dataType !== "moveObject") {
|
|
230
226
|
throw new Error("Price feed type mismatch");
|
|
231
227
|
}
|
|
232
|
-
this.priceFeedObjectIdCache.set(normalizedFeedId,
|
|
233
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
228
|
+
this.priceFeedObjectIdCache.set(normalizedFeedId, // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
234
229
|
// @ts-ignore
|
|
230
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
235
231
|
result.data.content.fields.value);
|
|
236
232
|
}
|
|
237
233
|
return this.priceFeedObjectIdCache.get(normalizedFeedId);
|
|
238
234
|
}
|
|
239
235
|
/**
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
async getPriceTableInfo() {
|
|
236
|
+
* Fetches the price table object id for the current state id if not cached
|
|
237
|
+
* @returns price table object id
|
|
238
|
+
*/ async getPriceTableInfo() {
|
|
244
239
|
if (this.priceTableInfo === undefined) {
|
|
245
240
|
const result = await this.provider.getDynamicFieldObject({
|
|
246
241
|
parentId: this.pythStateId,
|
|
247
242
|
name: {
|
|
248
243
|
type: "vector<u8>",
|
|
249
|
-
value: "price_info"
|
|
250
|
-
}
|
|
244
|
+
value: "price_info"
|
|
245
|
+
}
|
|
251
246
|
});
|
|
252
|
-
if (!result.data
|
|
247
|
+
if (!result.data?.type) {
|
|
253
248
|
throw new Error("Price Table not found, contract may not be initialized");
|
|
254
249
|
}
|
|
255
250
|
let type = result.data.type.replace("0x2::table::Table<", "");
|
|
256
251
|
type = type.replace("::price_identifier::PriceIdentifier, 0x2::object::ID>", "");
|
|
257
|
-
this.priceTableInfo = {
|
|
252
|
+
this.priceTableInfo = {
|
|
253
|
+
id: result.data.objectId,
|
|
254
|
+
fieldType: type
|
|
255
|
+
};
|
|
258
256
|
}
|
|
259
257
|
return this.priceTableInfo;
|
|
260
258
|
}
|
|
261
259
|
/**
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
extractVaaBytesFromAccumulatorMessage(accumulatorMessage) {
|
|
260
|
+
* Obtains the vaa bytes embedded in an accumulator message.
|
|
261
|
+
* @param accumulatorMessage - the accumulator price update message
|
|
262
|
+
* @returns vaa bytes as a uint8 array
|
|
263
|
+
*/ extractVaaBytesFromAccumulatorMessage(accumulatorMessage) {
|
|
267
264
|
// the first 6 bytes in the accumulator message encode the header, major, and minor bytes
|
|
268
265
|
// we ignore them, since we are only interested in the VAA bytes
|
|
269
266
|
const trailingPayloadSize = accumulatorMessage.readUint8(6);
|
|
270
267
|
const vaaSizeOffset = 7 + // header bytes (header(4) + major(1) + minor(1) + trailing payload size(1))
|
|
271
|
-
|
|
272
|
-
|
|
268
|
+
trailingPayloadSize + // trailing payload (variable number of bytes)
|
|
269
|
+
1; // proof_type (1 byte)
|
|
273
270
|
const vaaSize = accumulatorMessage.readUint16BE(vaaSizeOffset);
|
|
274
271
|
const vaaOffset = vaaSizeOffset + 2;
|
|
275
272
|
return accumulatorMessage.subarray(vaaOffset, vaaOffset + vaaSize);
|
|
276
273
|
}
|
|
277
274
|
}
|
|
278
|
-
exports.SuiPythClient = SuiPythClient;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { SuiPriceServiceConnection } from "./SuiPriceServiceConnection.js";
|
|
2
|
+
export { SuiPythClient } from "./client.js";
|
|
3
|
+
export type { AssetType, BinaryPriceUpdate, DurationInMs, DurationInSeconds, EncodingType, HermesClientConfig, HexString, PriceFeedMetadata, PriceIdInput, PriceUpdate, PublisherCaps, TwapsResponse, UnixTimestamp, } from "@pythnetwork/hermes-client";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "module" }
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pythnetwork/pyth-sui-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Pyth Network Sui Utilities",
|
|
5
5
|
"homepage": "https://pyth.network",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Pyth Data Association"
|
|
8
8
|
},
|
|
9
|
-
"main": "
|
|
10
|
-
"types": "
|
|
9
|
+
"main": "./dist/cjs/index.cjs",
|
|
10
|
+
"types": "./dist/cjs/index.d.ts",
|
|
11
|
+
"type": "module",
|
|
11
12
|
"files": [
|
|
12
|
-
"
|
|
13
|
+
"dist/**/*"
|
|
13
14
|
],
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
@@ -26,6 +27,8 @@
|
|
|
26
27
|
],
|
|
27
28
|
"license": "Apache-2.0",
|
|
28
29
|
"devDependencies": {
|
|
30
|
+
"@cprussin/eslint-config": "^4.0.2",
|
|
31
|
+
"@pythnetwork/jest-config": "",
|
|
29
32
|
"@truffle/hdwallet-provider": "^2.1.5",
|
|
30
33
|
"@types/ethereum-protocol": "^1.0.2",
|
|
31
34
|
"@types/jest": "^29.4.0",
|
|
@@ -34,27 +37,63 @@
|
|
|
34
37
|
"@types/yargs": "^17.0.20",
|
|
35
38
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
36
39
|
"@typescript-eslint/parser": "^6.0.0",
|
|
37
|
-
"eslint": "^
|
|
40
|
+
"eslint": "^9.23.0",
|
|
38
41
|
"jest": "^29.4.1",
|
|
39
42
|
"prettier": "^3.5.3",
|
|
40
|
-
"ts-jest": "^29.0.5",
|
|
41
|
-
"typescript": "^5.3.3",
|
|
42
43
|
"web3": "^1.8.2",
|
|
43
44
|
"yargs": "^17.0.20"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
47
|
"@mysten/sui": "^1.3.0",
|
|
47
48
|
"buffer": "^6.0.3",
|
|
48
|
-
"@pythnetwork/hermes-client": "2.
|
|
49
|
+
"@pythnetwork/hermes-client": "2.1.0"
|
|
49
50
|
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=22.14.0"
|
|
53
|
+
},
|
|
54
|
+
"exports": {
|
|
55
|
+
"./SuiPriceServiceConnection": {
|
|
56
|
+
"require": {
|
|
57
|
+
"types": "./dist/cjs/SuiPriceServiceConnection.d.ts",
|
|
58
|
+
"default": "./dist/cjs/SuiPriceServiceConnection.cjs"
|
|
59
|
+
},
|
|
60
|
+
"import": {
|
|
61
|
+
"types": "./dist/esm/SuiPriceServiceConnection.d.ts",
|
|
62
|
+
"default": "./dist/esm/SuiPriceServiceConnection.mjs"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"./client": {
|
|
66
|
+
"require": {
|
|
67
|
+
"types": "./dist/cjs/client.d.ts",
|
|
68
|
+
"default": "./dist/cjs/client.cjs"
|
|
69
|
+
},
|
|
70
|
+
"import": {
|
|
71
|
+
"types": "./dist/esm/client.d.ts",
|
|
72
|
+
"default": "./dist/esm/client.mjs"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
".": {
|
|
76
|
+
"require": {
|
|
77
|
+
"types": "./dist/cjs/index.d.ts",
|
|
78
|
+
"default": "./dist/cjs/index.cjs"
|
|
79
|
+
},
|
|
80
|
+
"import": {
|
|
81
|
+
"types": "./dist/esm/index.d.ts",
|
|
82
|
+
"default": "./dist/esm/index.mjs"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"./package.json": "./package.json"
|
|
86
|
+
},
|
|
87
|
+
"module": "./dist/esm/index.mjs",
|
|
50
88
|
"scripts": {
|
|
51
|
-
"build": "
|
|
89
|
+
"build": "ts-duality",
|
|
52
90
|
"example-relay": "node lib/examples/SuiRelay.js",
|
|
53
91
|
"test:lint": "eslint src/ --max-warnings 0",
|
|
54
92
|
"test:format": "prettier --check \"src/**/*.ts\"",
|
|
55
93
|
"fix:lint": "eslint src/ --fix --max-warnings 0",
|
|
56
94
|
"fix:format": "prettier --write \"src/**/*.ts\"",
|
|
57
95
|
"preversion": "pnpm run test:lint",
|
|
58
|
-
"version": "pnpm run format && git add -A src"
|
|
96
|
+
"version": "pnpm run format && git add -A src",
|
|
97
|
+
"clean": "rm -rf ./dist"
|
|
59
98
|
}
|
|
60
99
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SuiPriceServiceConnection.d.ts","sourceRoot":"","sources":["../src/SuiPriceServiceConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,SAAS,EAEV,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,qBAAa,yBAA0B,SAAQ,YAAY;IACzD;;;;;;;OAOG;IACG,uBAAuB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAUxE"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SuiPriceServiceConnection = void 0;
|
|
4
|
-
const hermes_client_1 = require("@pythnetwork/hermes-client");
|
|
5
|
-
const buffer_1 = require("buffer");
|
|
6
|
-
class SuiPriceServiceConnection extends hermes_client_1.HermesClient {
|
|
7
|
-
/**
|
|
8
|
-
* Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
|
|
9
|
-
* can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
|
|
10
|
-
* the price service returns a non-ok response (e.g: Invalid price ids)
|
|
11
|
-
*
|
|
12
|
-
* @param priceIds Array of hex-encoded price ids.
|
|
13
|
-
* @returns Array of buffers containing the price update data.
|
|
14
|
-
*/
|
|
15
|
-
async getPriceFeedsUpdateData(priceIds) {
|
|
16
|
-
// Fetch the latest price feed update VAAs from the price service
|
|
17
|
-
const updateData = await this.getLatestPriceUpdates(priceIds, {
|
|
18
|
-
encoding: "base64",
|
|
19
|
-
parsed: false,
|
|
20
|
-
});
|
|
21
|
-
return updateData.binary.data.map((update) => buffer_1.Buffer.from(update, "base64"));
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
exports.SuiPriceServiceConnection = SuiPriceServiceConnection;
|
package/lib/client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,KAAK,uBAAuB,GAAG;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,qBAAa,aAAa;IAOf,QAAQ,EAAE,SAAS;IACnB,WAAW,EAAE,QAAQ;IACrB,eAAe,EAAE,QAAQ;IARlC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,cAAc,CAAoD;IAC1E,OAAO,CAAC,sBAAsB,CAAuC;IACrE,OAAO,CAAC,aAAa,CAAqB;gBAEjC,QAAQ,EAAE,SAAS,EACnB,WAAW,EAAE,QAAQ,EACrB,eAAe,EAAE,QAAQ;IAM5B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAoBzC;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IA0BzD;;;;OAIG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW;;;;IAwB1C,yBAAyB,CAC7B,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,uBAAuB,CAAC;IA2B7B,uBAAuB,CAC3B,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,EAAE,EACpB,qBAAqB,EAAE,GAAG,EAC1B,KAAK,EAAE,uBAAuB,EAAE;IAgClC;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,SAAS,EAAE,GACnB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAuBtB;;;;;;OAMG;IACG,yBAAyB,CAC7B,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,SAAS,EAAE,EACpB,KAAK,EAAE,uBAAuB,EAAE,GAC/B,OAAO,CAAC,QAAQ,EAAE,CAAC;IAiBhB,eAAe,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE;IA2BxD;;OAEG;IACG,oBAAoB;IAO1B;;OAEG;IACG,gBAAgB;IAOtB;;;OAGG;IACG,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IA6B5E;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,QAAQ,CAAC;QAAC,SAAS,EAAE,QAAQ,CAAA;KAAE,CAAC;IAwBzE;;;;OAIG;IACH,qCAAqC,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM;CAY1E"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SuiRelay.d.ts","sourceRoot":"","sources":["../../src/examples/SuiRelay.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAsC/C,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,aAEtC"}
|
package/lib/examples/SuiRelay.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getProvider = getProvider;
|
|
7
|
-
const yargs_1 = __importDefault(require("yargs"));
|
|
8
|
-
const helpers_1 = require("yargs/helpers");
|
|
9
|
-
const client_1 = require("@mysten/sui/client");
|
|
10
|
-
const transactions_1 = require("@mysten/sui/transactions");
|
|
11
|
-
const ed25519_1 = require("@mysten/sui/keypairs/ed25519");
|
|
12
|
-
const buffer_1 = require("buffer");
|
|
13
|
-
const client_2 = require("../client");
|
|
14
|
-
const index_1 = require("../index");
|
|
15
|
-
const argvPromise = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
16
|
-
.option("feed-id", {
|
|
17
|
-
description: "Price feed ids to update without the leading 0x (e.g f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b). Can be provided multiple times for multiple feed updates",
|
|
18
|
-
string: true,
|
|
19
|
-
type: "array",
|
|
20
|
-
demandOption: true,
|
|
21
|
-
})
|
|
22
|
-
.option("hermes", {
|
|
23
|
-
description: "Endpoint URL for Hermes. e.g: https://hermes.pyth.network",
|
|
24
|
-
type: "string",
|
|
25
|
-
demandOption: true,
|
|
26
|
-
})
|
|
27
|
-
.option("full-node", {
|
|
28
|
-
description: "URL of the full Sui node RPC endpoint. e.g: https://fullnode.testnet.sui.io:443",
|
|
29
|
-
type: "string",
|
|
30
|
-
demandOption: true,
|
|
31
|
-
})
|
|
32
|
-
.option("pyth-state-id", {
|
|
33
|
-
description: "Pyth state object id.",
|
|
34
|
-
type: "string",
|
|
35
|
-
demandOption: true,
|
|
36
|
-
})
|
|
37
|
-
.option("wormhole-state-id", {
|
|
38
|
-
description: "Wormhole state object id.",
|
|
39
|
-
type: "string",
|
|
40
|
-
demandOption: true,
|
|
41
|
-
}).argv;
|
|
42
|
-
function getProvider(url) {
|
|
43
|
-
return new client_1.SuiClient({ url });
|
|
44
|
-
}
|
|
45
|
-
async function run() {
|
|
46
|
-
if (process.env.SUI_KEY === undefined) {
|
|
47
|
-
throw new Error(`SUI_KEY environment variable should be set.`);
|
|
48
|
-
}
|
|
49
|
-
const argv = await argvPromise;
|
|
50
|
-
// Fetch the latest price feed update data from the Price Service
|
|
51
|
-
const connection = new index_1.SuiPriceServiceConnection(argv["hermes"]);
|
|
52
|
-
const feeds = argv["feed-id"];
|
|
53
|
-
if (!Array.isArray(feeds)) {
|
|
54
|
-
throw new Error("Not a valid input!");
|
|
55
|
-
}
|
|
56
|
-
const provider = getProvider(argv["full-node"]);
|
|
57
|
-
const wormholeStateId = argv["wormhole-state-id"];
|
|
58
|
-
const pythStateId = argv["pyth-state-id"];
|
|
59
|
-
const client = new client_2.SuiPythClient(provider, pythStateId, wormholeStateId);
|
|
60
|
-
const newFeeds = [];
|
|
61
|
-
const existingFeeds = [];
|
|
62
|
-
for (const feed of feeds) {
|
|
63
|
-
if (typeof feed !== "string") {
|
|
64
|
-
throw new Error(`Not a valid string input ${feed}`);
|
|
65
|
-
}
|
|
66
|
-
if ((await client.getPriceFeedObjectId(feed)) == undefined) {
|
|
67
|
-
newFeeds.push(feed);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
existingFeeds.push(feed);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
console.log({
|
|
74
|
-
newFeeds,
|
|
75
|
-
existingFeeds,
|
|
76
|
-
});
|
|
77
|
-
const tx = new transactions_1.Transaction();
|
|
78
|
-
if (existingFeeds.length > 0) {
|
|
79
|
-
const updateData = await connection.getPriceFeedsUpdateData(existingFeeds);
|
|
80
|
-
await client.updatePriceFeeds(tx, updateData, existingFeeds);
|
|
81
|
-
}
|
|
82
|
-
if (newFeeds.length > 0) {
|
|
83
|
-
const updateData = await connection.getPriceFeedsUpdateData(newFeeds);
|
|
84
|
-
await client.createPriceFeed(tx, updateData);
|
|
85
|
-
}
|
|
86
|
-
const wallet = ed25519_1.Ed25519Keypair.fromSecretKey(buffer_1.Buffer.from(process.env.SUI_KEY, "hex"));
|
|
87
|
-
tx.setGasBudget(1000000);
|
|
88
|
-
const result = await provider.signAndExecuteTransaction({
|
|
89
|
-
signer: wallet,
|
|
90
|
-
transaction: tx,
|
|
91
|
-
options: {
|
|
92
|
-
showEffects: true,
|
|
93
|
-
showEvents: true,
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
console.dir(result, { depth: null });
|
|
97
|
-
}
|
|
98
|
-
run();
|
package/lib/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { SuiPriceServiceConnection } from "./SuiPriceServiceConnection";
|
|
2
|
-
export { SuiPythClient } from "./client";
|
|
3
|
-
export { AssetType, BinaryPriceUpdate, DurationInMs, DurationInSeconds, EncodingType, HermesClientConfig, HexString, PriceFeedMetadata, PriceIdInput, PriceUpdate, PublisherCaps, TwapsResponse, UnixTimestamp, } from "@pythnetwork/hermes-client";
|
|
4
|
-
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,4BAA4B,CAAC"}
|
package/lib/index.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SuiPythClient = exports.SuiPriceServiceConnection = void 0;
|
|
4
|
-
var SuiPriceServiceConnection_1 = require("./SuiPriceServiceConnection");
|
|
5
|
-
Object.defineProperty(exports, "SuiPriceServiceConnection", { enumerable: true, get: function () { return SuiPriceServiceConnection_1.SuiPriceServiceConnection; } });
|
|
6
|
-
var client_1 = require("./client");
|
|
7
|
-
Object.defineProperty(exports, "SuiPythClient", { enumerable: true, get: function () { return client_1.SuiPythClient; } });
|