@pythnetwork/price-pusher 9.1.0 → 9.3.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/README.md +115 -0
- package/lib/aptos/balance-tracker.d.ts +46 -0
- package/lib/aptos/balance-tracker.d.ts.map +1 -0
- package/lib/aptos/balance-tracker.js +61 -0
- package/lib/aptos/command.d.ts +2 -0
- package/lib/aptos/command.d.ts.map +1 -1
- package/lib/aptos/command.js +46 -9
- package/lib/controller.d.ts +3 -0
- package/lib/controller.d.ts.map +1 -1
- package/lib/controller.js +37 -1
- package/lib/evm/balance-tracker.d.ts +42 -0
- package/lib/evm/balance-tracker.d.ts.map +1 -0
- package/lib/evm/balance-tracker.js +49 -0
- package/lib/evm/command.d.ts +2 -0
- package/lib/evm/command.d.ts.map +1 -1
- package/lib/evm/command.js +47 -10
- package/lib/evm/pyth-contract.d.ts.map +1 -1
- package/lib/evm/super-wallet.d.ts.map +1 -1
- package/lib/evm/super-wallet.js +17 -7
- package/lib/fuel/command.js +17 -7
- package/lib/index.js +3 -0
- package/lib/injective/command.d.ts +1 -0
- package/lib/injective/command.d.ts.map +1 -1
- package/lib/injective/command.js +26 -10
- package/lib/injective/injective.d.ts +26 -10
- package/lib/injective/injective.d.ts.map +1 -1
- package/lib/injective/injective.js +125 -83
- package/lib/interface.d.ts +51 -0
- package/lib/interface.d.ts.map +1 -1
- package/lib/interface.js +80 -1
- package/lib/metrics.d.ts +22 -0
- package/lib/metrics.d.ts.map +1 -0
- package/lib/metrics.js +113 -0
- package/lib/near/command.js +17 -7
- package/lib/options.d.ts +6 -0
- package/lib/options.d.ts.map +1 -1
- package/lib/options.js +17 -1
- package/lib/price-config.d.ts.map +1 -1
- package/lib/price-config.js +5 -1
- package/lib/solana/balance-tracker.d.ts +42 -0
- package/lib/solana/balance-tracker.d.ts.map +1 -0
- package/lib/solana/balance-tracker.js +51 -0
- package/lib/solana/command.d.ts +2 -0
- package/lib/solana/command.d.ts.map +1 -1
- package/lib/solana/command.js +48 -10
- package/lib/solana/solana.d.ts.map +1 -1
- package/lib/solana/solana.js +1 -1
- package/lib/sui/balance-tracker.d.ts +39 -0
- package/lib/sui/balance-tracker.d.ts.map +1 -0
- package/lib/sui/balance-tracker.js +54 -0
- package/lib/sui/command.d.ts +2 -0
- package/lib/sui/command.d.ts.map +1 -1
- package/lib/sui/command.js +50 -12
- package/lib/sui/sui.d.ts.map +1 -1
- package/lib/ton/command.js +17 -7
- package/lib/utils.d.ts +2 -2
- package/lib/utils.d.ts.map +1 -1
- package/package.json +31 -26
package/lib/evm/super-wallet.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
36
|
exports.createClient = void 0;
|
|
27
37
|
const viem_1 = require("viem");
|
package/lib/fuel/command.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
package/lib/index.js
CHANGED
|
@@ -14,12 +14,15 @@ const command_5 = __importDefault(require("./near/command"));
|
|
|
14
14
|
const command_6 = __importDefault(require("./solana/command"));
|
|
15
15
|
const command_7 = __importDefault(require("./fuel/command"));
|
|
16
16
|
const command_8 = __importDefault(require("./ton/command"));
|
|
17
|
+
const options_1 = require("./options");
|
|
17
18
|
(0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
18
19
|
.parserConfiguration({
|
|
19
20
|
"parse-numbers": false,
|
|
20
21
|
})
|
|
21
22
|
.config("config")
|
|
22
23
|
.global("config")
|
|
24
|
+
.option("enable-metrics", options_1.enableMetrics["enable-metrics"])
|
|
25
|
+
.option("metrics-port", options_1.metricsPort["metrics-port"])
|
|
23
26
|
.command(command_2.default)
|
|
24
27
|
.command(command_7.default)
|
|
25
28
|
.command(command_1.default)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/injective/command.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;yBAevB,OAAO;iBAKP,OAAO;qBAIP,OAAO;0BAIP,OAAO;;oBAUiB,GAAG;;
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/injective/command.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;yBAevB,OAAO;iBAKP,OAAO;qBAIP,OAAO;0BAIP,OAAO;wCAMP,OAAO;;oBAUiB,GAAG;;AAxCpC,wBA4HE"}
|
package/lib/injective/command.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
@@ -53,12 +63,17 @@ exports.default = {
|
|
|
53
63
|
required: true,
|
|
54
64
|
},
|
|
55
65
|
"gas-price": {
|
|
56
|
-
description: "Gas price to be used for each
|
|
66
|
+
description: "Gas price to be used for each transaction",
|
|
57
67
|
type: "number",
|
|
58
68
|
},
|
|
59
69
|
"gas-multiplier": {
|
|
60
|
-
description: "Gas multiplier to be used for each
|
|
70
|
+
description: "Gas multiplier to be used for each transaction",
|
|
71
|
+
type: "number",
|
|
72
|
+
},
|
|
73
|
+
"price-ids-process-chunk-size": {
|
|
74
|
+
description: "Set in case we wanna split price feeds updates into chunks to have smaller transactions. Set to -1 to disable chunking.",
|
|
61
75
|
type: "number",
|
|
76
|
+
required: false,
|
|
62
77
|
},
|
|
63
78
|
...options.priceConfigFile,
|
|
64
79
|
...options.priceServiceEndpoint,
|
|
@@ -71,7 +86,7 @@ exports.default = {
|
|
|
71
86
|
},
|
|
72
87
|
handler: async function (argv) {
|
|
73
88
|
// FIXME: type checks for this
|
|
74
|
-
const {
|
|
89
|
+
const { network, logLevel, gasPrice, grpcEndpoint, mnemonicFile, gasMultiplier, priceConfigFile, pollingFrequency, pushingFrequency, controllerLogLevel, pythContractAddress, priceServiceEndpoint, priceIdsProcessChunkSize, } = argv;
|
|
75
90
|
const logger = (0, pino_1.default)({ level: logLevel });
|
|
76
91
|
if (network !== "testnet" && network !== "mainnet") {
|
|
77
92
|
throw new Error("Please specify network. One of [testnet, mainnet]");
|
|
@@ -96,6 +111,7 @@ exports.default = {
|
|
|
96
111
|
chainId: (0, networks_1.getNetworkInfo)(network).chainId,
|
|
97
112
|
gasPrice,
|
|
98
113
|
gasMultiplier,
|
|
114
|
+
priceIdsProcessChunkSize,
|
|
99
115
|
});
|
|
100
116
|
const controller = new controller_1.Controller(priceConfigs, pythListener, injectiveListener, injectivePusher, logger.child({ module: "Controller" }, { level: controllerLogLevel }), { pushingFrequency });
|
|
101
117
|
controller.start();
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { HexString, HermesClient } from "@pythnetwork/hermes-client";
|
|
2
|
-
import {
|
|
2
|
+
import { PriceItem, PriceInfo, IPricePusher, ChainPriceListener } from "../interface";
|
|
3
3
|
import { DurationInSeconds } from "../utils";
|
|
4
4
|
import { Logger } from "pino";
|
|
5
|
+
type InjectiveConfig = {
|
|
6
|
+
chainId: string;
|
|
7
|
+
gasMultiplier: number;
|
|
8
|
+
gasPrice: number;
|
|
9
|
+
priceIdsProcessChunkSize: number;
|
|
10
|
+
};
|
|
5
11
|
export declare class InjectivePriceListener extends ChainPriceListener {
|
|
6
12
|
private pythContractAddress;
|
|
7
13
|
private grpcEndpoint;
|
|
@@ -11,24 +17,34 @@ export declare class InjectivePriceListener extends ChainPriceListener {
|
|
|
11
17
|
});
|
|
12
18
|
getOnChainPriceInfo(priceId: HexString): Promise<PriceInfo | undefined>;
|
|
13
19
|
}
|
|
14
|
-
type InjectiveConfig = {
|
|
15
|
-
chainId: string;
|
|
16
|
-
gasMultiplier: number;
|
|
17
|
-
gasPrice: number;
|
|
18
|
-
};
|
|
19
20
|
export declare class InjectivePricePusher implements IPricePusher {
|
|
20
21
|
private hermesClient;
|
|
21
22
|
private pythContractAddress;
|
|
22
23
|
private grpcEndpoint;
|
|
23
24
|
private logger;
|
|
24
|
-
private
|
|
25
|
+
private mnemonic;
|
|
25
26
|
private chainConfig;
|
|
26
|
-
private
|
|
27
|
+
private accounts; /** { address: Account } */
|
|
27
28
|
constructor(hermesClient: HermesClient, pythContractAddress: string, grpcEndpoint: string, logger: Logger, mnemonic: string, chainConfig?: Partial<InjectiveConfig>);
|
|
28
|
-
private
|
|
29
|
+
private getWallet;
|
|
29
30
|
private signAndBroadcastMsg;
|
|
30
|
-
getPriceFeedUpdateObject(priceIds: string[]): Promise<any>;
|
|
31
31
|
updatePriceFeed(priceIds: string[], pubTimesToPush: number[]): Promise<void>;
|
|
32
|
+
private updatePriceFeedChunk;
|
|
33
|
+
/**
|
|
34
|
+
* Get the fee for the transaction (using simulation).
|
|
35
|
+
*
|
|
36
|
+
* We also apply a multiplier to the gas used to apply a small
|
|
37
|
+
* buffer to the gas that'll be used.
|
|
38
|
+
*/
|
|
39
|
+
private getStdFee;
|
|
40
|
+
/**
|
|
41
|
+
* Get the latest VAAs for updatePriceFeed and then push them
|
|
42
|
+
*/
|
|
43
|
+
private getPriceFeedUpdateObject;
|
|
44
|
+
/**
|
|
45
|
+
* Get the update fee for the given VAAs (i.e the fee that is paid to the pyth contract)
|
|
46
|
+
*/
|
|
47
|
+
private getUpdateFee;
|
|
32
48
|
}
|
|
33
49
|
export {};
|
|
34
50
|
//# sourceMappingURL=injective.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injective.d.ts","sourceRoot":"","sources":["../../src/injective/injective.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"injective.d.ts","sourceRoot":"","sources":["../../src/injective/injective.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EACL,SAAS,EACT,SAAS,EACT,YAAY,EACZ,kBAAkB,EACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAa7C,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAmB9B,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB,EAAE,MAAM,CAAC;CAClC,CAAC;AAGF,qBAAa,sBAAuB,SAAQ,kBAAkB;IAE1D,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,YAAY;IAEpB,OAAO,CAAC,MAAM;gBAHN,mBAAmB,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,EAC5B,UAAU,EAAE,SAAS,EAAE,EACf,MAAM,EAAE,MAAM,EACtB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAKG,mBAAmB,CACvB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CA4BlC;AAED,qBAAa,oBAAqB,YAAW,YAAY;IAOrD,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,MAAM;IAThB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,QAAQ,CACX,CAAC,2BAA2B;gBAGvB,YAAY,EAAE,YAAY,EAC1B,mBAAmB,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAaxC,OAAO,CAAC,SAAS;YAWH,mBAAmB;IA+C3B,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;YAuBF,oBAAoB;IA+ClC;;;;;OAKG;YACW,SAAS;IA0CvB;;OAEG;YACW,wBAAwB;IAsBtC;;OAEG;YACW,YAAY;CAwB3B"}
|
|
@@ -3,8 +3,10 @@ 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 utils_1 = require("@injectivelabs/utils");
|
|
6
7
|
const DEFAULT_GAS_PRICE = 160000000;
|
|
7
8
|
const DEFAULT_GAS_MULTIPLIER = 1.05;
|
|
9
|
+
const DEFAULT_PRICE_IDS_PROCESS_CHUNK_SIZE = -1;
|
|
8
10
|
const INJECTIVE_TESTNET_CHAIN_ID = "injective-888";
|
|
9
11
|
// this use price without leading 0x
|
|
10
12
|
class InjectivePriceListener extends interface_1.ChainPriceListener {
|
|
@@ -43,142 +45,182 @@ class InjectivePricePusher {
|
|
|
43
45
|
pythContractAddress;
|
|
44
46
|
grpcEndpoint;
|
|
45
47
|
logger;
|
|
46
|
-
|
|
48
|
+
mnemonic;
|
|
47
49
|
chainConfig;
|
|
48
|
-
|
|
50
|
+
accounts = {}; /** { address: Account } */
|
|
49
51
|
constructor(hermesClient, pythContractAddress, grpcEndpoint, logger, mnemonic, chainConfig) {
|
|
50
52
|
this.hermesClient = hermesClient;
|
|
51
53
|
this.pythContractAddress = pythContractAddress;
|
|
52
54
|
this.grpcEndpoint = grpcEndpoint;
|
|
53
55
|
this.logger = logger;
|
|
54
|
-
this.
|
|
56
|
+
this.mnemonic = mnemonic;
|
|
55
57
|
this.chainConfig = {
|
|
56
58
|
chainId: chainConfig?.chainId ?? INJECTIVE_TESTNET_CHAIN_ID,
|
|
57
59
|
gasMultiplier: chainConfig?.gasMultiplier ?? DEFAULT_GAS_MULTIPLIER,
|
|
58
60
|
gasPrice: chainConfig?.gasPrice ?? DEFAULT_GAS_PRICE,
|
|
61
|
+
priceIdsProcessChunkSize: chainConfig?.priceIdsProcessChunkSize ??
|
|
62
|
+
DEFAULT_PRICE_IDS_PROCESS_CHUNK_SIZE,
|
|
59
63
|
};
|
|
60
64
|
}
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
getWallet(index) {
|
|
66
|
+
if (this.chainConfig.priceIdsProcessChunkSize === -1 ||
|
|
67
|
+
this.chainConfig.priceIdsProcessChunkSize === undefined) {
|
|
68
|
+
return sdk_ts_1.PrivateKey.fromMnemonic(this.mnemonic);
|
|
69
|
+
}
|
|
70
|
+
return sdk_ts_1.PrivateKey.fromMnemonic(this.mnemonic, `m/44'/60'/0'/0/${index}`);
|
|
63
71
|
}
|
|
64
|
-
async signAndBroadcastMsg(msg) {
|
|
72
|
+
async signAndBroadcastMsg(msg, index) {
|
|
65
73
|
const chainGrpcAuthApi = new sdk_ts_1.ChainGrpcAuthApi(this.grpcEndpoint);
|
|
74
|
+
const wallet = this.getWallet(index);
|
|
75
|
+
const injectiveAddress = wallet.toAddress().toBech32();
|
|
66
76
|
// Fetch the latest account details only if it's not stored.
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
accountNumber: this.account.baseAccount.accountNumber,
|
|
71
|
-
message: msg,
|
|
72
|
-
chainId: this.chainConfig.chainId,
|
|
73
|
-
pubKey: this.wallet.toPublicKey().toBase64(),
|
|
74
|
-
});
|
|
75
|
-
const txService = new sdk_ts_1.TxGrpcClient(this.grpcEndpoint);
|
|
76
|
-
// simulation
|
|
77
|
+
this.accounts[injectiveAddress] ??=
|
|
78
|
+
await chainGrpcAuthApi.fetchAccount(injectiveAddress);
|
|
79
|
+
const account = this.accounts[injectiveAddress];
|
|
77
80
|
try {
|
|
78
|
-
const { gasInfo: { gasUsed }, } = await txService.simulate(simulateTxRaw);
|
|
79
|
-
// simulation returns us the approximate gas used
|
|
80
|
-
// gas passed with the transaction should be more than that
|
|
81
|
-
// in order for it to be successfully executed
|
|
82
|
-
// this multiplier takes care of that
|
|
83
|
-
const gas = (gasUsed * this.chainConfig.gasMultiplier).toFixed();
|
|
84
|
-
const fee = {
|
|
85
|
-
amount: [
|
|
86
|
-
{
|
|
87
|
-
denom: "inj",
|
|
88
|
-
amount: (Number(gas) * this.chainConfig.gasPrice).toFixed(),
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
gas,
|
|
92
|
-
};
|
|
93
81
|
const { signBytes, txRaw } = (0, sdk_ts_1.createTransactionFromMsg)({
|
|
94
|
-
sequence:
|
|
95
|
-
accountNumber:
|
|
82
|
+
sequence: account.baseAccount.sequence,
|
|
83
|
+
accountNumber: account.baseAccount.accountNumber,
|
|
96
84
|
message: msg,
|
|
97
85
|
chainId: this.chainConfig.chainId,
|
|
98
|
-
fee,
|
|
99
|
-
pubKey:
|
|
86
|
+
fee: await this.getStdFee(msg, index),
|
|
87
|
+
pubKey: wallet.toPublicKey().toBase64(),
|
|
100
88
|
});
|
|
101
|
-
const sig = await
|
|
102
|
-
this.account.baseAccount.sequence++;
|
|
89
|
+
const sig = await wallet.sign(Buffer.from(signBytes));
|
|
103
90
|
/** Append Signatures */
|
|
104
91
|
txRaw.signatures = [sig];
|
|
105
92
|
// this takes approx 5 seconds
|
|
106
|
-
const txResponse = await
|
|
93
|
+
const txResponse = await new sdk_ts_1.TxGrpcApi(this.grpcEndpoint).broadcast(txRaw);
|
|
94
|
+
account.baseAccount.sequence++;
|
|
107
95
|
return txResponse;
|
|
108
96
|
}
|
|
109
97
|
catch (e) {
|
|
110
|
-
// The sequence number was invalid and hence we will have to fetch it again
|
|
98
|
+
// The sequence number was invalid and hence we will have to fetch it again
|
|
111
99
|
if (JSON.stringify(e).match(/account sequence mismatch/) !== null) {
|
|
112
|
-
|
|
113
|
-
this.account = null;
|
|
100
|
+
this.accounts[injectiveAddress] = undefined;
|
|
114
101
|
}
|
|
115
102
|
throw e;
|
|
116
103
|
}
|
|
117
104
|
}
|
|
118
|
-
async getPriceFeedUpdateObject(priceIds) {
|
|
119
|
-
const response = await this.hermesClient.getLatestPriceUpdates(priceIds, {
|
|
120
|
-
encoding: "base64",
|
|
121
|
-
});
|
|
122
|
-
const vaas = response.binary.data;
|
|
123
|
-
return {
|
|
124
|
-
update_price_feeds: {
|
|
125
|
-
data: vaas,
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
105
|
async updatePriceFeed(priceIds, pubTimesToPush) {
|
|
130
106
|
if (priceIds.length === 0) {
|
|
131
107
|
return;
|
|
132
108
|
}
|
|
133
109
|
if (priceIds.length !== pubTimesToPush.length)
|
|
134
110
|
throw new Error("Invalid arguments");
|
|
135
|
-
|
|
111
|
+
const priceIdChunks = this.chainConfig.priceIdsProcessChunkSize === -1
|
|
112
|
+
? [priceIds]
|
|
113
|
+
: (0, utils_1.splitArrayToChunks)({
|
|
114
|
+
array: priceIds,
|
|
115
|
+
chunkSize: Number(this.chainConfig.priceIdsProcessChunkSize),
|
|
116
|
+
});
|
|
117
|
+
await Promise.all(priceIdChunks.map((priceIdChunk, chunkIndex) => this.updatePriceFeedChunk(priceIdChunk, chunkIndex)));
|
|
118
|
+
}
|
|
119
|
+
async updatePriceFeedChunk(priceIds, chunkIndex) {
|
|
136
120
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
121
|
+
const priceFeedUpdateObject = await this.getPriceFeedUpdateObject(priceIds);
|
|
122
|
+
const updateFeeQueryResponse = await this.getUpdateFee(priceFeedUpdateObject.update_price_feeds.data);
|
|
123
|
+
const wallet = this.getWallet(chunkIndex);
|
|
124
|
+
const msg = sdk_ts_1.MsgExecuteContract.fromJSON({
|
|
125
|
+
sender: wallet.toAddress().toBech32(),
|
|
126
|
+
contractAddress: this.pythContractAddress,
|
|
127
|
+
msg: priceFeedUpdateObject,
|
|
128
|
+
funds: [updateFeeQueryResponse],
|
|
129
|
+
});
|
|
130
|
+
const rs = await this.signAndBroadcastMsg(msg, chunkIndex);
|
|
131
|
+
this.logger.info({ hash: rs.txHash }, `Successfully broadcasted txHash for chunk ${chunkIndex}`);
|
|
139
132
|
}
|
|
140
133
|
catch (err) {
|
|
141
|
-
|
|
142
|
-
|
|
134
|
+
if (err.message.match(/account inj[a-zA-Z0-9]+ not found/) !== null) {
|
|
135
|
+
this.logger.error(err, `Account not found for chunk ${chunkIndex}`);
|
|
136
|
+
throw new Error("Please check the mnemonic");
|
|
137
|
+
}
|
|
138
|
+
if (err.message.match(/insufficient/) !== null &&
|
|
139
|
+
err.message.match(/funds/) !== null) {
|
|
140
|
+
this.logger.error(err, `Insufficient funds for chunk ${chunkIndex}`);
|
|
141
|
+
throw new Error("Insufficient funds");
|
|
142
|
+
}
|
|
143
|
+
this.logger.error(err, `Error executing messages for chunk ${chunkIndex}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get the fee for the transaction (using simulation).
|
|
148
|
+
*
|
|
149
|
+
* We also apply a multiplier to the gas used to apply a small
|
|
150
|
+
* buffer to the gas that'll be used.
|
|
151
|
+
*/
|
|
152
|
+
async getStdFee(msg, index) {
|
|
153
|
+
const wallet = this.getWallet(index);
|
|
154
|
+
const injectiveAddress = wallet.toAddress().toBech32();
|
|
155
|
+
const account = this.accounts[injectiveAddress];
|
|
156
|
+
if (!account) {
|
|
157
|
+
throw new Error("Account not found");
|
|
143
158
|
}
|
|
144
|
-
|
|
159
|
+
const { txRaw: simulateTxRaw } = (0, sdk_ts_1.createTransactionFromMsg)({
|
|
160
|
+
sequence: account.baseAccount.sequence,
|
|
161
|
+
accountNumber: account.baseAccount.accountNumber,
|
|
162
|
+
message: msg,
|
|
163
|
+
chainId: this.chainConfig.chainId,
|
|
164
|
+
pubKey: wallet.toPublicKey().toBase64(),
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
const result = await new sdk_ts_1.TxGrpcApi(this.grpcEndpoint).simulate(simulateTxRaw);
|
|
168
|
+
const gas = (result.gasInfo.gasUsed * this.chainConfig.gasMultiplier).toFixed();
|
|
169
|
+
const fee = {
|
|
170
|
+
amount: [
|
|
171
|
+
{
|
|
172
|
+
denom: "inj",
|
|
173
|
+
amount: (Number(gas) * this.chainConfig.gasPrice).toFixed(),
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
gas,
|
|
177
|
+
};
|
|
178
|
+
return fee;
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
this.logger.error(err, `Error getting std fee`);
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get the latest VAAs for updatePriceFeed and then push them
|
|
187
|
+
*/
|
|
188
|
+
async getPriceFeedUpdateObject(priceIds) {
|
|
189
|
+
try {
|
|
190
|
+
const response = await this.hermesClient.getLatestPriceUpdates(priceIds, {
|
|
191
|
+
encoding: "base64",
|
|
192
|
+
});
|
|
193
|
+
const vaas = response.binary.data;
|
|
194
|
+
return {
|
|
195
|
+
update_price_feeds: {
|
|
196
|
+
data: vaas,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
this.logger.error(err, `Error fetching the latest vaas to push`);
|
|
202
|
+
throw err;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get the update fee for the given VAAs (i.e the fee that is paid to the pyth contract)
|
|
207
|
+
*/
|
|
208
|
+
async getUpdateFee(vaas) {
|
|
145
209
|
try {
|
|
146
210
|
const api = new sdk_ts_1.ChainGrpcWasmApi(this.grpcEndpoint);
|
|
147
211
|
const { data } = await api.fetchSmartContractState(this.pythContractAddress, Buffer.from(JSON.stringify({
|
|
148
212
|
get_update_fee: {
|
|
149
|
-
vaas
|
|
213
|
+
vaas,
|
|
150
214
|
},
|
|
151
215
|
})).toString("base64"));
|
|
152
216
|
const json = Buffer.from(data).toString();
|
|
153
|
-
|
|
217
|
+
return JSON.parse(json);
|
|
154
218
|
}
|
|
155
219
|
catch (err) {
|
|
156
|
-
this.logger.error(err,
|
|
220
|
+
this.logger.error(err, `Error fetching update fee.`);
|
|
157
221
|
// Throwing an error because it is likely an RPC issue
|
|
158
222
|
throw err;
|
|
159
223
|
}
|
|
160
|
-
try {
|
|
161
|
-
const executeMsg = sdk_ts_1.MsgExecuteContract.fromJSON({
|
|
162
|
-
sender: this.injectiveAddress(),
|
|
163
|
-
contractAddress: this.pythContractAddress,
|
|
164
|
-
msg: priceFeedUpdateObject,
|
|
165
|
-
funds: [updateFeeQueryResponse],
|
|
166
|
-
});
|
|
167
|
-
const rs = await this.signAndBroadcastMsg(executeMsg);
|
|
168
|
-
this.logger.info({ hash: rs.txHash }, "Succesfully broadcasted txHash");
|
|
169
|
-
}
|
|
170
|
-
catch (err) {
|
|
171
|
-
if (err.message.match(/account inj[a-zA-Z0-9]+ not found/) !== null) {
|
|
172
|
-
this.logger.error(err, "Account not found");
|
|
173
|
-
throw new Error("Please check the mnemonic");
|
|
174
|
-
}
|
|
175
|
-
if (err.message.match(/insufficient/) !== null &&
|
|
176
|
-
err.message.match(/funds/) !== null) {
|
|
177
|
-
this.logger.error(err, "Insufficient funds");
|
|
178
|
-
throw new Error("Insufficient funds");
|
|
179
|
-
}
|
|
180
|
-
this.logger.error(err, "Error executing messages");
|
|
181
|
-
}
|
|
182
224
|
}
|
|
183
225
|
}
|
|
184
226
|
exports.InjectivePricePusher = InjectivePricePusher;
|
package/lib/interface.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { HexString, UnixTimestamp } from "@pythnetwork/hermes-client";
|
|
2
2
|
import { DurationInSeconds } from "./utils";
|
|
3
|
+
import { Logger } from "pino";
|
|
4
|
+
import { PricePusherMetrics } from "./metrics";
|
|
3
5
|
export type PriceItem = {
|
|
4
6
|
id: HexString;
|
|
5
7
|
alias: string;
|
|
@@ -28,4 +30,53 @@ export declare abstract class ChainPriceListener implements IPriceListener {
|
|
|
28
30
|
export interface IPricePusher {
|
|
29
31
|
updatePriceFeed(priceIds: string[], pubTimesToPush: UnixTimestamp[]): Promise<void>;
|
|
30
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Common configuration properties for all balance trackers
|
|
35
|
+
*/
|
|
36
|
+
export interface BaseBalanceTrackerConfig {
|
|
37
|
+
/** Address of the wallet to track */
|
|
38
|
+
address: string;
|
|
39
|
+
/** Name/ID of the network/chain */
|
|
40
|
+
network: string;
|
|
41
|
+
/** How often to update the balance */
|
|
42
|
+
updateInterval: DurationInSeconds;
|
|
43
|
+
/** Metrics instance to report balance updates */
|
|
44
|
+
metrics: PricePusherMetrics;
|
|
45
|
+
/** Logger instance */
|
|
46
|
+
logger: Logger;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Interface for all balance trackers to implement
|
|
50
|
+
* Each chain will have its own implementation of this interface
|
|
51
|
+
*/
|
|
52
|
+
export interface IBalanceTracker {
|
|
53
|
+
/**
|
|
54
|
+
* Start tracking the wallet balance
|
|
55
|
+
*/
|
|
56
|
+
start(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Stop tracking the wallet balance
|
|
59
|
+
*/
|
|
60
|
+
stop(): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Abstract base class that implements common functionality for all balance trackers
|
|
64
|
+
*/
|
|
65
|
+
export declare abstract class BaseBalanceTracker implements IBalanceTracker {
|
|
66
|
+
protected address: string;
|
|
67
|
+
protected network: string;
|
|
68
|
+
protected updateInterval: DurationInSeconds;
|
|
69
|
+
protected metrics: PricePusherMetrics;
|
|
70
|
+
protected logger: Logger;
|
|
71
|
+
protected isRunning: boolean;
|
|
72
|
+
constructor(config: BaseBalanceTrackerConfig);
|
|
73
|
+
start(): Promise<void>;
|
|
74
|
+
private startUpdateLoop;
|
|
75
|
+
/**
|
|
76
|
+
* Chain-specific balance update implementation
|
|
77
|
+
* Each chain will implement this method differently
|
|
78
|
+
*/
|
|
79
|
+
protected abstract updateBalance(): Promise<void>;
|
|
80
|
+
stop(): void;
|
|
81
|
+
}
|
|
31
82
|
//# sourceMappingURL=interface.d.ts.map
|
package/lib/interface.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,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,gBAAgB;IACxB,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE;IALnC,OAAO,CAAC,eAAe,CAA4B;IACnD,SAAS,CAAC,cAAc,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBAGvC,gBAAgB,EAAE,iBAAiB,EACjC,UAAU,EAAE,SAAS,EAAE;IAQ7B,KAAK;YAMG,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;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,cAAc,EAAE,iBAAiB,CAAC;IAClC,iDAAiD;IACjD,OAAO,EAAE,kBAAkB,CAAC;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,IAAI,IAAI,IAAI,CAAC;CACd;AAED;;GAEG;AACH,8BAAsB,kBAAmB,YAAW,eAAe;IACjE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC5C,SAAS,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACtC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,SAAS,EAAE,OAAO,CAAS;gBAEzB,MAAM,EAAE,wBAAwB;IAQ/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAcrB,eAAe;IAkB7B;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAE1C,IAAI,IAAI,IAAI;CAGpB"}
|