@pythnetwork/price-pusher 4.1.2 → 5.4.2
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/README.md +36 -2
- package/lib/aptos/aptos.d.ts +31 -0
- package/lib/aptos/aptos.d.ts.map +1 -0
- package/lib/aptos/aptos.js +139 -0
- package/lib/aptos/command.d.ts +18 -0
- package/lib/aptos/command.d.ts.map +1 -0
- package/lib/aptos/command.js +82 -0
- package/lib/common.d.ts +5 -0
- package/lib/common.d.ts.map +1 -0
- package/lib/common.js +2 -0
- package/lib/controller.d.ts +2 -1
- package/lib/controller.d.ts.map +1 -0
- package/lib/controller.js +10 -2
- package/lib/evm/command.d.ts +1 -0
- package/lib/evm/command.d.ts.map +1 -0
- package/lib/evm/command.js +3 -0
- package/lib/evm/custom-gas-station.d.ts +1 -0
- package/lib/evm/custom-gas-station.d.ts.map +1 -0
- package/lib/evm/evm.d.ts +1 -0
- package/lib/evm/evm.d.ts.map +1 -0
- package/lib/evm/evm.js +9 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +4 -0
- package/lib/injective/command.d.ts +2 -0
- package/lib/injective/command.d.ts.map +1 -0
- package/lib/injective/command.js +13 -2
- package/lib/injective/injective.d.ts +2 -0
- package/lib/injective/injective.d.ts.map +1 -0
- package/lib/injective/injective.js +35 -34
- package/lib/interface.d.ts +1 -0
- package/lib/interface.d.ts.map +1 -0
- package/lib/options.d.ts +1 -0
- package/lib/options.d.ts.map +1 -0
- package/lib/price-config.d.ts +10 -1
- package/lib/price-config.d.ts.map +1 -0
- package/lib/price-config.js +39 -10
- package/lib/pyth-price-listener.d.ts +1 -0
- package/lib/pyth-price-listener.d.ts.map +1 -0
- package/lib/sui/command.d.ts +24 -0
- package/lib/sui/command.d.ts.map +1 -0
- package/lib/sui/command.js +132 -0
- package/lib/sui/sui.d.ts +42 -0
- package/lib/sui/sui.d.ts.map +1 -0
- package/lib/sui/sui.js +358 -0
- package/lib/utils.d.ts +1 -0
- package/lib/utils.d.ts.map +1 -0
- package/package.json +5 -3
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.InjectivePricePusher = exports.InjectivePriceListener = void 0;
|
|
4
4
|
const interface_1 = require("../interface");
|
|
5
5
|
const sdk_ts_1 = require("@injectivelabs/sdk-ts");
|
|
6
|
-
const
|
|
6
|
+
const DEFAULT_GAS_PRICE = 500000000;
|
|
7
7
|
// this use price without leading 0x
|
|
8
8
|
class InjectivePriceListener extends interface_1.ChainPriceListener {
|
|
9
9
|
pythContractAddress;
|
|
@@ -18,7 +18,7 @@ class InjectivePriceListener extends interface_1.ChainPriceListener {
|
|
|
18
18
|
try {
|
|
19
19
|
const api = new sdk_ts_1.ChainGrpcWasmApi(this.grpcEndpoint);
|
|
20
20
|
const { data } = await api.fetchSmartContractState(this.pythContractAddress, Buffer.from(`{"price_feed":{"id":"${priceId}"}}`).toString("base64"));
|
|
21
|
-
const json = Buffer.from(data
|
|
21
|
+
const json = Buffer.from(data).toString();
|
|
22
22
|
priceQueryResponse = JSON.parse(json);
|
|
23
23
|
}
|
|
24
24
|
catch (e) {
|
|
@@ -41,6 +41,7 @@ class InjectivePricePusher {
|
|
|
41
41
|
grpcEndpoint;
|
|
42
42
|
wallet;
|
|
43
43
|
chainConfig;
|
|
44
|
+
account = null;
|
|
44
45
|
constructor(priceServiceConnection, pythContractAddress, grpcEndpoint, mnemonic, chainConfig) {
|
|
45
46
|
this.priceServiceConnection = priceServiceConnection;
|
|
46
47
|
this.pythContractAddress = pythContractAddress;
|
|
@@ -49,7 +50,7 @@ class InjectivePricePusher {
|
|
|
49
50
|
this.chainConfig = {
|
|
50
51
|
chainId: chainConfig?.chainId ?? "injective-888",
|
|
51
52
|
gasMultiplier: chainConfig?.gasMultiplier ?? 1.2,
|
|
52
|
-
gasPrice: chainConfig?.gasPrice ??
|
|
53
|
+
gasPrice: chainConfig?.gasPrice ?? DEFAULT_GAS_PRICE,
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
injectiveAddress() {
|
|
@@ -57,10 +58,11 @@ class InjectivePricePusher {
|
|
|
57
58
|
}
|
|
58
59
|
async signAndBroadcastMsg(msg) {
|
|
59
60
|
const chainGrpcAuthApi = new sdk_ts_1.ChainGrpcAuthApi(this.grpcEndpoint);
|
|
60
|
-
|
|
61
|
+
// Fetch the latest account details only if it's not stored.
|
|
62
|
+
this.account ??= await chainGrpcAuthApi.fetchAccount(this.injectiveAddress());
|
|
61
63
|
const { txRaw: simulateTxRaw } = (0, sdk_ts_1.createTransactionFromMsg)({
|
|
62
|
-
sequence: account.baseAccount.sequence,
|
|
63
|
-
accountNumber: account.baseAccount.accountNumber,
|
|
64
|
+
sequence: this.account.baseAccount.sequence,
|
|
65
|
+
accountNumber: this.account.baseAccount.accountNumber,
|
|
64
66
|
message: msg,
|
|
65
67
|
chainId: this.chainConfig.chainId,
|
|
66
68
|
pubKey: this.wallet.toPublicKey().toBase64(),
|
|
@@ -72,30 +74,41 @@ class InjectivePricePusher {
|
|
|
72
74
|
// gas passed with the transaction should be more than that
|
|
73
75
|
// in order for it to be successfully executed
|
|
74
76
|
// this multiplier takes care of that
|
|
77
|
+
const gas = (gasUsed * this.chainConfig.gasMultiplier).toFixed();
|
|
75
78
|
const fee = {
|
|
76
79
|
amount: [
|
|
77
80
|
{
|
|
78
81
|
denom: "inj",
|
|
79
|
-
amount: (
|
|
80
|
-
this.chainConfig.gasPrice *
|
|
81
|
-
this.chainConfig.gasMultiplier).toFixed(),
|
|
82
|
+
amount: (Number(gas) * this.chainConfig.gasPrice).toFixed(),
|
|
82
83
|
},
|
|
83
84
|
],
|
|
84
|
-
gas
|
|
85
|
+
gas,
|
|
85
86
|
};
|
|
86
87
|
const { signBytes, txRaw } = (0, sdk_ts_1.createTransactionFromMsg)({
|
|
87
|
-
sequence: account.baseAccount.sequence,
|
|
88
|
-
accountNumber: account.baseAccount.accountNumber,
|
|
88
|
+
sequence: this.account.baseAccount.sequence,
|
|
89
|
+
accountNumber: this.account.baseAccount.accountNumber,
|
|
89
90
|
message: msg,
|
|
90
91
|
chainId: this.chainConfig.chainId,
|
|
91
92
|
fee,
|
|
92
93
|
pubKey: this.wallet.toPublicKey().toBase64(),
|
|
93
94
|
});
|
|
94
95
|
const sig = await this.wallet.sign(Buffer.from(signBytes));
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
try {
|
|
97
|
+
this.account.baseAccount.sequence++;
|
|
98
|
+
/** Append Signatures */
|
|
99
|
+
txRaw.signatures = [sig];
|
|
100
|
+
// this takes approx 5 seconds
|
|
101
|
+
const txResponse = await txService.broadcast(txRaw);
|
|
102
|
+
return txResponse;
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
// The sequence number was invalid and hence we will have to fetch it again.
|
|
106
|
+
if (JSON.stringify(e).match(/account sequence mismatch/) !== null) {
|
|
107
|
+
// We need to fetch the account details again.
|
|
108
|
+
this.account = null;
|
|
109
|
+
}
|
|
110
|
+
throw e;
|
|
111
|
+
}
|
|
99
112
|
}
|
|
100
113
|
async getPriceFeedUpdateObject(priceIds) {
|
|
101
114
|
const vaas = await this.priceServiceConnection.getLatestVaas(priceIds);
|
|
@@ -121,22 +134,12 @@ class InjectivePricePusher {
|
|
|
121
134
|
console.error(e);
|
|
122
135
|
return;
|
|
123
136
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
},
|
|
131
|
-
})).toString("base64"));
|
|
132
|
-
const json = Buffer.from(data, "base64").toString();
|
|
133
|
-
updateFeeQueryResponse = JSON.parse(json);
|
|
134
|
-
}
|
|
135
|
-
catch (e) {
|
|
136
|
-
console.error("Error fetching update fee");
|
|
137
|
-
console.error(e);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
137
|
+
// In order to reduce the number of API calls
|
|
138
|
+
// We are calculating the fee using the same logic as in contract.
|
|
139
|
+
const updateFeeQueryResponse = {
|
|
140
|
+
denom: "inj",
|
|
141
|
+
amount: priceFeedUpdateObject.update_price_feeds.data.length.toFixed(),
|
|
142
|
+
};
|
|
140
143
|
try {
|
|
141
144
|
const executeMsg = sdk_ts_1.MsgExecuteContract.fromJSON({
|
|
142
145
|
sender: this.injectiveAddress(),
|
|
@@ -145,8 +148,6 @@ class InjectivePricePusher {
|
|
|
145
148
|
funds: [updateFeeQueryResponse],
|
|
146
149
|
});
|
|
147
150
|
const rs = await this.signAndBroadcastMsg(executeMsg);
|
|
148
|
-
if (rs.code !== 0)
|
|
149
|
-
throw new Error("Error: transaction failed");
|
|
150
151
|
console.log("Succesfully broadcasted txHash:", rs.txHash);
|
|
151
152
|
}
|
|
152
153
|
catch (e) {
|
package/lib/interface.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,aAAa,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,cAAc;IAE7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;CAC5D;AAED,8BAAsB,kBAAmB,YAAW,cAAc;IAK9D,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,gBAAgB;IACxB,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE;IANnC,OAAO,CAAC,eAAe,CAA4B;IACnD,SAAS,CAAC,cAAc,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBAGvC,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,iBAAiB,EACjC,UAAU,EAAE,SAAS,EAAE;IAQ7B,KAAK;YASG,UAAU;IASxB,SAAS,CAAC,qBAAqB,CAC7B,OAAO,EAAE,SAAS,EAClB,aAAa,EAAE,SAAS;IAkB1B,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI1D,QAAQ,CAAC,mBAAmB,CAC1B,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,eAAe,CACb,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,aAAa,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
|
package/lib/options.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,eAAO,MAAM,oBAAoB;;CAOhC,CAAC;AAEF,eAAO,MAAM,mBAAmB;;CAQ/B,CAAC;AAEF,eAAO,MAAM,eAAe;;CAM3B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;CAQ5B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;CAU5B,CAAC;AAEF,eAAO,MAAM,YAAY;;CAMxB,CAAC"}
|
package/lib/price-config.d.ts
CHANGED
|
@@ -7,12 +7,21 @@ export type PriceConfig = {
|
|
|
7
7
|
timeDifference: DurationInSeconds;
|
|
8
8
|
priceDeviation: PctNumber;
|
|
9
9
|
confidenceRatio: PctNumber;
|
|
10
|
+
earlyUpdateTimeDifference: DurationInSeconds | undefined;
|
|
11
|
+
earlyUpdatePriceDeviation: PctNumber | undefined;
|
|
12
|
+
earlyUpdateConfidenceRatio: PctNumber | undefined;
|
|
10
13
|
};
|
|
11
14
|
export declare function readPriceConfigFile(path: string): PriceConfig[];
|
|
15
|
+
export declare enum UpdateCondition {
|
|
16
|
+
YES = 0,
|
|
17
|
+
EARLY = 1,
|
|
18
|
+
NO = 2
|
|
19
|
+
}
|
|
12
20
|
/**
|
|
13
21
|
* Checks whether on-chain price needs to be updated with the latest pyth price information.
|
|
14
22
|
*
|
|
15
23
|
* @param priceConfig Config of the price feed to check
|
|
16
24
|
* @returns True if the on-chain price needs to be updated.
|
|
17
25
|
*/
|
|
18
|
-
export declare function shouldUpdate(priceConfig: PriceConfig, sourceLatestPrice: PriceInfo | undefined, targetLatestPrice: PriceInfo | undefined):
|
|
26
|
+
export declare function shouldUpdate(priceConfig: PriceConfig, sourceLatestPrice: PriceInfo | undefined, targetLatestPrice: PriceInfo | undefined): UpdateCondition;
|
|
27
|
+
//# sourceMappingURL=price-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"price-config.d.ts","sourceRoot":"","sources":["../src/price-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAI9D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAmB,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAuBxC,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,SAAS,CAAC;IACd,cAAc,EAAE,iBAAiB,CAAC;IAClC,cAAc,EAAE,SAAS,CAAC;IAC1B,eAAe,EAAE,SAAS,CAAC;IAI3B,yBAAyB,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACzD,yBAAyB,EAAE,SAAS,GAAG,SAAS,CAAC;IACjD,0BAA0B,EAAE,SAAS,GAAG,SAAS,CAAC;CACnD,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAsB/D;AAED,oBAAY,eAAe;IAEzB,GAAG,IAAA;IAEH,KAAK,IAAA;IAEL,EAAE,IAAA;CACH;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,SAAS,GAAG,SAAS,EACxC,iBAAiB,EAAE,SAAS,GAAG,SAAS,GACvC,eAAe,CAmEjB"}
|
package/lib/price-config.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.shouldUpdate = exports.readPriceConfigFile = void 0;
|
|
6
|
+
exports.shouldUpdate = exports.UpdateCondition = exports.readPriceConfigFile = void 0;
|
|
7
7
|
const joi_1 = __importDefault(require("joi"));
|
|
8
8
|
const yaml_1 = __importDefault(require("yaml"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -17,6 +17,11 @@ const PriceConfigFileSchema = joi_1.default.array()
|
|
|
17
17
|
time_difference: joi_1.default.number().required(),
|
|
18
18
|
price_deviation: joi_1.default.number().required(),
|
|
19
19
|
confidence_ratio: joi_1.default.number().required(),
|
|
20
|
+
early_update: joi_1.default.object({
|
|
21
|
+
time_difference: joi_1.default.number().optional(),
|
|
22
|
+
price_deviation: joi_1.default.number().optional(),
|
|
23
|
+
confidence_ratio: joi_1.default.number().optional(),
|
|
24
|
+
}).optional(),
|
|
20
25
|
}))
|
|
21
26
|
.unique("id")
|
|
22
27
|
.unique("alias")
|
|
@@ -34,11 +39,23 @@ function readPriceConfigFile(path) {
|
|
|
34
39
|
timeDifference: priceConfigRaw.time_difference,
|
|
35
40
|
priceDeviation: priceConfigRaw.price_deviation,
|
|
36
41
|
confidenceRatio: priceConfigRaw.confidence_ratio,
|
|
42
|
+
earlyUpdateTimeDifference: priceConfigRaw.early_update?.time_difference,
|
|
43
|
+
earlyUpdatePriceDeviation: priceConfigRaw.early_update?.price_deviation,
|
|
44
|
+
earlyUpdateConfidenceRatio: priceConfigRaw.early_update?.confidence_ratio,
|
|
37
45
|
};
|
|
38
46
|
return priceConfig;
|
|
39
47
|
});
|
|
40
48
|
}
|
|
41
49
|
exports.readPriceConfigFile = readPriceConfigFile;
|
|
50
|
+
var UpdateCondition;
|
|
51
|
+
(function (UpdateCondition) {
|
|
52
|
+
// This price feed must be updated
|
|
53
|
+
UpdateCondition[UpdateCondition["YES"] = 0] = "YES";
|
|
54
|
+
// This price feed may be updated as part of a larger batch
|
|
55
|
+
UpdateCondition[UpdateCondition["EARLY"] = 1] = "EARLY";
|
|
56
|
+
// This price feed shouldn't be updated
|
|
57
|
+
UpdateCondition[UpdateCondition["NO"] = 2] = "NO";
|
|
58
|
+
})(UpdateCondition = exports.UpdateCondition || (exports.UpdateCondition = {}));
|
|
42
59
|
/**
|
|
43
60
|
* Checks whether on-chain price needs to be updated with the latest pyth price information.
|
|
44
61
|
*
|
|
@@ -49,16 +66,16 @@ function shouldUpdate(priceConfig, sourceLatestPrice, targetLatestPrice) {
|
|
|
49
66
|
const priceId = priceConfig.id;
|
|
50
67
|
// There is no price to update the target with.
|
|
51
68
|
if (sourceLatestPrice === undefined) {
|
|
52
|
-
return
|
|
69
|
+
return UpdateCondition.YES;
|
|
53
70
|
}
|
|
54
71
|
// It means that price never existed there. So we should push the latest price feed.
|
|
55
72
|
if (targetLatestPrice === undefined) {
|
|
56
73
|
console.log(`${priceConfig.alias} (${priceId}) is not available on the target network. Pushing the price.`);
|
|
57
|
-
return
|
|
74
|
+
return UpdateCondition.YES;
|
|
58
75
|
}
|
|
59
76
|
// The current price is not newer than the price onchain
|
|
60
77
|
if (sourceLatestPrice.publishTime < targetLatestPrice.publishTime) {
|
|
61
|
-
return
|
|
78
|
+
return UpdateCondition.NO;
|
|
62
79
|
}
|
|
63
80
|
const timeDifference = sourceLatestPrice.publishTime - targetLatestPrice.publishTime;
|
|
64
81
|
const priceDeviationPct = (Math.abs(Number(sourceLatestPrice.price) - Number(targetLatestPrice.price)) /
|
|
@@ -68,12 +85,24 @@ function shouldUpdate(priceConfig, sourceLatestPrice, targetLatestPrice) {
|
|
|
68
85
|
console.log(`Analyzing price ${priceConfig.alias} (${priceId})`);
|
|
69
86
|
console.log("Source latest price: ", sourceLatestPrice);
|
|
70
87
|
console.log("Target latest price: ", targetLatestPrice);
|
|
71
|
-
console.log(`Time difference: ${timeDifference} (< ${priceConfig.timeDifference}?) OR ` +
|
|
72
|
-
`Price deviation: ${priceDeviationPct.toFixed(5)}% (< ${priceConfig.priceDeviation}%?) OR ` +
|
|
73
|
-
`Confidence ratio: ${confidenceRatioPct.toFixed(5)}% (< ${priceConfig.confidenceRatio}%?)`);
|
|
74
|
-
|
|
88
|
+
console.log(`Time difference: ${timeDifference} (< ${priceConfig.timeDifference}? / early: < ${priceConfig.earlyUpdateTimeDifference}) OR ` +
|
|
89
|
+
`Price deviation: ${priceDeviationPct.toFixed(5)}% (< ${priceConfig.priceDeviation}%? / early: < ${priceConfig.earlyUpdatePriceDeviation}%?) OR ` +
|
|
90
|
+
`Confidence ratio: ${confidenceRatioPct.toFixed(5)}% (< ${priceConfig.confidenceRatio}%? / early: < ${priceConfig.earlyUpdatePriceDeviation}%?)`);
|
|
91
|
+
if (timeDifference >= priceConfig.timeDifference ||
|
|
75
92
|
priceDeviationPct >= priceConfig.priceDeviation ||
|
|
76
|
-
confidenceRatioPct >= priceConfig.confidenceRatio
|
|
77
|
-
|
|
93
|
+
confidenceRatioPct >= priceConfig.confidenceRatio) {
|
|
94
|
+
return UpdateCondition.YES;
|
|
95
|
+
}
|
|
96
|
+
else if ((priceConfig.earlyUpdateTimeDifference !== undefined &&
|
|
97
|
+
timeDifference >= priceConfig.earlyUpdateTimeDifference) ||
|
|
98
|
+
(priceConfig.earlyUpdatePriceDeviation !== undefined &&
|
|
99
|
+
priceDeviationPct >= priceConfig.earlyUpdatePriceDeviation) ||
|
|
100
|
+
(priceConfig.earlyUpdateConfidenceRatio !== undefined &&
|
|
101
|
+
confidenceRatioPct >= priceConfig.earlyUpdateConfidenceRatio)) {
|
|
102
|
+
return UpdateCondition.EARLY;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
return UpdateCondition.NO;
|
|
106
|
+
}
|
|
78
107
|
}
|
|
79
108
|
exports.shouldUpdate = shouldUpdate;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pyth-price-listener.d.ts","sourceRoot":"","sources":["../src/pyth-price-listener.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,sBAAsB,EACvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnE,qBAAa,iBAAkB,YAAW,cAAc;IACtD,OAAO,CAAC,UAAU,CAAyB;IAC3C,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,eAAe,CAA4B;gBAEvC,UAAU,EAAE,sBAAsB,EAAE,UAAU,EAAE,SAAS,EAAE;IAWjE,KAAK;IAmBX,OAAO,CAAC,cAAc;IAsBtB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;CAG3D"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Options } from "yargs";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
command: string;
|
|
4
|
+
describe: string;
|
|
5
|
+
builder: {
|
|
6
|
+
"pushing-frequency": Options;
|
|
7
|
+
"polling-frequency": Options;
|
|
8
|
+
"mnemonic-file": Options;
|
|
9
|
+
"price-service-endpoint": Options;
|
|
10
|
+
"price-config-file": Options;
|
|
11
|
+
endpoint: Options;
|
|
12
|
+
"pyth-package-id": Options;
|
|
13
|
+
"pyth-state-id": Options;
|
|
14
|
+
"wormhole-package-id": Options;
|
|
15
|
+
"wormhole-state-id": Options;
|
|
16
|
+
"price-feed-to-price-info-object-table-id": Options;
|
|
17
|
+
"max-vaas-per-ptb": Options;
|
|
18
|
+
"num-gas-objects": Options;
|
|
19
|
+
"gas-budget": Options;
|
|
20
|
+
};
|
|
21
|
+
handler: (argv: any) => Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
export default _default;
|
|
24
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/sui/command.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;oBAgFC,GAAG;;AA5EpC,wBA8JE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const price_service_client_1 = require("@pythnetwork/price-service-client");
|
|
30
|
+
const options = __importStar(require("../options"));
|
|
31
|
+
const price_config_1 = require("../price-config");
|
|
32
|
+
const fs_1 = __importDefault(require("fs"));
|
|
33
|
+
const pyth_price_listener_1 = require("../pyth-price-listener");
|
|
34
|
+
const controller_1 = require("../controller");
|
|
35
|
+
const sui_1 = require("./sui");
|
|
36
|
+
const sui_js_1 = require("@mysten/sui.js");
|
|
37
|
+
exports.default = {
|
|
38
|
+
command: "sui",
|
|
39
|
+
describe: "Run price pusher for sui. Most of the arguments below are" +
|
|
40
|
+
"network specific, so there's one set of values for mainnet and" +
|
|
41
|
+
"another for testnet. See config.sui..sample.json for the " +
|
|
42
|
+
"appropriate values for your network. ",
|
|
43
|
+
builder: {
|
|
44
|
+
endpoint: {
|
|
45
|
+
description: "RPC endpoint URL for sui. The pusher will periodically" +
|
|
46
|
+
"poll for updates. The polling interval is configurable via the " +
|
|
47
|
+
"`polling-frequency` command-line argument.",
|
|
48
|
+
type: "string",
|
|
49
|
+
required: true,
|
|
50
|
+
},
|
|
51
|
+
"pyth-package-id": {
|
|
52
|
+
description: "Pyth Package Id. Can be found here" +
|
|
53
|
+
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
|
54
|
+
type: "string",
|
|
55
|
+
required: true,
|
|
56
|
+
},
|
|
57
|
+
"pyth-state-id": {
|
|
58
|
+
description: "Pyth State Id. Can be found here" +
|
|
59
|
+
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
|
60
|
+
type: "string",
|
|
61
|
+
required: true,
|
|
62
|
+
},
|
|
63
|
+
"wormhole-package-id": {
|
|
64
|
+
description: "Wormhole Package Id. Can be found here" +
|
|
65
|
+
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
|
66
|
+
type: "string",
|
|
67
|
+
required: true,
|
|
68
|
+
},
|
|
69
|
+
"wormhole-state-id": {
|
|
70
|
+
description: "Wormhole State Id. Can be found here" +
|
|
71
|
+
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
|
72
|
+
type: "string",
|
|
73
|
+
required: true,
|
|
74
|
+
},
|
|
75
|
+
"price-feed-to-price-info-object-table-id": {
|
|
76
|
+
description: "This is the id of the table which stored the information related to price data. You can find it here: " +
|
|
77
|
+
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
|
78
|
+
type: "string",
|
|
79
|
+
required: true,
|
|
80
|
+
},
|
|
81
|
+
"max-vaas-per-ptb": {
|
|
82
|
+
description: "Maximum number of VAAs that can be included in a single PTB.",
|
|
83
|
+
type: "number",
|
|
84
|
+
required: true,
|
|
85
|
+
default: 1,
|
|
86
|
+
},
|
|
87
|
+
"num-gas-objects": {
|
|
88
|
+
description: "Number of gas objects in the pool.",
|
|
89
|
+
type: "number",
|
|
90
|
+
required: true,
|
|
91
|
+
default: 30,
|
|
92
|
+
},
|
|
93
|
+
"gas-budget": {
|
|
94
|
+
description: "Gas budget for each price update",
|
|
95
|
+
type: "number",
|
|
96
|
+
required: true,
|
|
97
|
+
default: 500_000_000,
|
|
98
|
+
},
|
|
99
|
+
...options.priceConfigFile,
|
|
100
|
+
...options.priceServiceEndpoint,
|
|
101
|
+
...options.mnemonicFile,
|
|
102
|
+
...options.pollingFrequency,
|
|
103
|
+
...options.pushingFrequency,
|
|
104
|
+
},
|
|
105
|
+
handler: async function (argv) {
|
|
106
|
+
const { endpoint, priceConfigFile, priceServiceEndpoint, mnemonicFile, pushingFrequency, pollingFrequency, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, priceFeedToPriceInfoObjectTableId, maxVaasPerPtb, numGasObjects, gasBudget, } = argv;
|
|
107
|
+
const priceConfigs = (0, price_config_1.readPriceConfigFile)(priceConfigFile);
|
|
108
|
+
const priceServiceConnection = new price_service_client_1.PriceServiceConnection(priceServiceEndpoint, {
|
|
109
|
+
logger: {
|
|
110
|
+
// Log only warnings and errors from the price service client
|
|
111
|
+
info: () => undefined,
|
|
112
|
+
warn: console.warn,
|
|
113
|
+
error: console.error,
|
|
114
|
+
debug: () => undefined,
|
|
115
|
+
trace: () => undefined,
|
|
116
|
+
},
|
|
117
|
+
priceFeedRequestConfig: {
|
|
118
|
+
binary: true,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
const mnemonic = fs_1.default.readFileSync(mnemonicFile, "utf-8").trim();
|
|
122
|
+
console.log(`Pushing updates from wallet address: ${sui_js_1.Ed25519Keypair.deriveKeypair(mnemonic)
|
|
123
|
+
.getPublicKey()
|
|
124
|
+
.toSuiAddress()}`);
|
|
125
|
+
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
|
|
126
|
+
const pythListener = new pyth_price_listener_1.PythPriceListener(priceServiceConnection, priceItems);
|
|
127
|
+
const suiListener = new sui_1.SuiPriceListener(pythPackageId, priceFeedToPriceInfoObjectTableId, endpoint, priceItems, { pollingFrequency });
|
|
128
|
+
const suiPusher = await sui_1.SuiPricePusher.createWithAutomaticGasPool(priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, priceFeedToPriceInfoObjectTableId, maxVaasPerPtb, endpoint, mnemonic, gasBudget, numGasObjects);
|
|
129
|
+
const controller = new controller_1.Controller(priceConfigs, pythListener, suiListener, suiPusher, { pushingFrequency });
|
|
130
|
+
controller.start();
|
|
131
|
+
},
|
|
132
|
+
};
|
package/lib/sui/sui.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ChainPriceListener, IPricePusher, PriceInfo, PriceItem } from "../interface";
|
|
2
|
+
import { DurationInSeconds } from "../utils";
|
|
3
|
+
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
|
4
|
+
import { RawSigner, SuiObjectRef } from "@mysten/sui.js";
|
|
5
|
+
export declare class SuiPriceListener extends ChainPriceListener {
|
|
6
|
+
private pythPackageId;
|
|
7
|
+
private priceFeedToPriceInfoObjectTableId;
|
|
8
|
+
private endpoint;
|
|
9
|
+
constructor(pythPackageId: string, priceFeedToPriceInfoObjectTableId: string, endpoint: string, priceItems: PriceItem[], config: {
|
|
10
|
+
pollingFrequency: DurationInSeconds;
|
|
11
|
+
});
|
|
12
|
+
getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined>;
|
|
13
|
+
}
|
|
14
|
+
export declare class SuiPricePusher implements IPricePusher {
|
|
15
|
+
private readonly signer;
|
|
16
|
+
private priceServiceConnection;
|
|
17
|
+
private pythPackageId;
|
|
18
|
+
private pythStateId;
|
|
19
|
+
private wormholePackageId;
|
|
20
|
+
private wormholeStateId;
|
|
21
|
+
private priceFeedToPriceInfoObjectTableId;
|
|
22
|
+
private maxVaasPerPtb;
|
|
23
|
+
private gasBudget;
|
|
24
|
+
private gasPool;
|
|
25
|
+
constructor(signer: RawSigner, priceServiceConnection: PriceServiceConnection, pythPackageId: string, pythStateId: string, wormholePackageId: string, wormholeStateId: string, priceFeedToPriceInfoObjectTableId: string, maxVaasPerPtb: number, endpoint: string, mnemonic: string, gasBudget: number, gasPool: SuiObjectRef[]);
|
|
26
|
+
/**
|
|
27
|
+
* Create a price pusher with a pool of `numGasObjects` gas coins that will be used to send transactions.
|
|
28
|
+
* The gas coins of the wallet for the provided mnemonic will be merged and then evenly split into `numGasObjects`.
|
|
29
|
+
*/
|
|
30
|
+
static createWithAutomaticGasPool(priceServiceConnection: PriceServiceConnection, pythPackageId: string, pythStateId: string, wormholePackageId: string, wormholeStateId: string, priceFeedToPriceInfoObjectTableId: string, maxVaasPerPtb: number, endpoint: string, mnemonic: string, gasBudget: number, numGasObjects: number): Promise<SuiPricePusher>;
|
|
31
|
+
updatePriceFeed(priceIds: string[], pubTimesToPush: number[]): Promise<void>;
|
|
32
|
+
private createPriceUpdateTransaction;
|
|
33
|
+
/** Send every transaction in txs in parallel, returning when all transactions have completed. */
|
|
34
|
+
private sendTransactionBlocks;
|
|
35
|
+
/** Send a single transaction block using a gas coin from the pool. */
|
|
36
|
+
private sendTransactionBlock;
|
|
37
|
+
private static initializeGasPool;
|
|
38
|
+
private static getAllGasCoins;
|
|
39
|
+
private static splitGasCoinEqually;
|
|
40
|
+
private static mergeGasCoinsIntoOne;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=sui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sui.d.ts","sourceRoot":"","sources":["../../src/sui/sui.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAIL,SAAS,EAIT,YAAY,EAKb,MAAM,gBAAgB,CAAC;AAMxB,qBAAa,gBAAiB,SAAQ,kBAAkB;IAEpD,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,iCAAiC;IACzC,OAAO,CAAC,QAAQ;gBAFR,aAAa,EAAE,MAAM,EACrB,iCAAiC,EAAE,MAAM,EACzC,QAAQ,EAAE,MAAM,EACxB,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAKG,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAmD3E;AAED,qBAAa,cAAe,YAAW,YAAY;IAE/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,iCAAiC;IACzC,OAAO,CAAC,aAAa;IAGrB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,OAAO;gBAXE,MAAM,EAAE,SAAS,EAC1B,sBAAsB,EAAE,sBAAsB,EAC9C,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,eAAe,EAAE,MAAM,EACvB,iCAAiC,EAAE,MAAM,EACzC,aAAa,EAAE,MAAM,EAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EACR,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,YAAY,EAAE;IAGjC;;;OAGG;WACU,0BAA0B,CACrC,sBAAsB,EAAE,sBAAsB,EAC9C,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,eAAe,EAAE,MAAM,EACvB,iCAAiC,EAAE,MAAM,EACzC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,CAAC;IAiCpB,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;YAsDF,4BAA4B;IA2E1C,iGAAiG;YACnF,qBAAqB;IAMnC,sEAAsE;YACxD,oBAAoB;mBA6Cb,iBAAiB;mBA2BjB,cAAc;mBAiCd,mBAAmB;mBAsCnB,oBAAoB;CA2C1C"}
|