@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.
Files changed (58) hide show
  1. package/README.md +115 -0
  2. package/lib/aptos/balance-tracker.d.ts +46 -0
  3. package/lib/aptos/balance-tracker.d.ts.map +1 -0
  4. package/lib/aptos/balance-tracker.js +61 -0
  5. package/lib/aptos/command.d.ts +2 -0
  6. package/lib/aptos/command.d.ts.map +1 -1
  7. package/lib/aptos/command.js +46 -9
  8. package/lib/controller.d.ts +3 -0
  9. package/lib/controller.d.ts.map +1 -1
  10. package/lib/controller.js +37 -1
  11. package/lib/evm/balance-tracker.d.ts +42 -0
  12. package/lib/evm/balance-tracker.d.ts.map +1 -0
  13. package/lib/evm/balance-tracker.js +49 -0
  14. package/lib/evm/command.d.ts +2 -0
  15. package/lib/evm/command.d.ts.map +1 -1
  16. package/lib/evm/command.js +47 -10
  17. package/lib/evm/pyth-contract.d.ts.map +1 -1
  18. package/lib/evm/super-wallet.d.ts.map +1 -1
  19. package/lib/evm/super-wallet.js +17 -7
  20. package/lib/fuel/command.js +17 -7
  21. package/lib/index.js +3 -0
  22. package/lib/injective/command.d.ts +1 -0
  23. package/lib/injective/command.d.ts.map +1 -1
  24. package/lib/injective/command.js +26 -10
  25. package/lib/injective/injective.d.ts +26 -10
  26. package/lib/injective/injective.d.ts.map +1 -1
  27. package/lib/injective/injective.js +125 -83
  28. package/lib/interface.d.ts +51 -0
  29. package/lib/interface.d.ts.map +1 -1
  30. package/lib/interface.js +80 -1
  31. package/lib/metrics.d.ts +22 -0
  32. package/lib/metrics.d.ts.map +1 -0
  33. package/lib/metrics.js +113 -0
  34. package/lib/near/command.js +17 -7
  35. package/lib/options.d.ts +6 -0
  36. package/lib/options.d.ts.map +1 -1
  37. package/lib/options.js +17 -1
  38. package/lib/price-config.d.ts.map +1 -1
  39. package/lib/price-config.js +5 -1
  40. package/lib/solana/balance-tracker.d.ts +42 -0
  41. package/lib/solana/balance-tracker.d.ts.map +1 -0
  42. package/lib/solana/balance-tracker.js +51 -0
  43. package/lib/solana/command.d.ts +2 -0
  44. package/lib/solana/command.d.ts.map +1 -1
  45. package/lib/solana/command.js +48 -10
  46. package/lib/solana/solana.d.ts.map +1 -1
  47. package/lib/solana/solana.js +1 -1
  48. package/lib/sui/balance-tracker.d.ts +39 -0
  49. package/lib/sui/balance-tracker.d.ts.map +1 -0
  50. package/lib/sui/balance-tracker.js +54 -0
  51. package/lib/sui/command.d.ts +2 -0
  52. package/lib/sui/command.d.ts.map +1 -1
  53. package/lib/sui/command.js +50 -12
  54. package/lib/sui/sui.d.ts.map +1 -1
  55. package/lib/ton/command.js +17 -7
  56. package/lib/utils.d.ts +2 -2
  57. package/lib/utils.d.ts.map +1 -1
  58. package/package.json +31 -26
@@ -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 (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
- };
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");
@@ -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 (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
- };
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)
@@ -15,6 +15,7 @@ declare const _default: {
15
15
  network: Options;
16
16
  "gas-price": Options;
17
17
  "gas-multiplier": Options;
18
+ "price-ids-process-chunk-size": Options;
18
19
  };
19
20
  handler: (argv: any) => Promise<void>;
20
21
  };
@@ -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;;AAlCpC,wBAoHE"}
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"}
@@ -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 (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
- };
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 transasction",
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 transasction",
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 { gasPrice, gasMultiplier, grpcEndpoint, priceConfigFile, priceServiceEndpoint, mnemonicFile, pythContractAddress, pushingFrequency, pollingFrequency, network, logLevel, controllerLogLevel, } = argv;
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 { IPricePusher, PriceInfo, ChainPriceListener, PriceItem } from "../interface";
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 wallet;
25
+ private mnemonic;
25
26
  private chainConfig;
26
- private account;
27
+ private accounts; /** { address: Account } */
27
28
  constructor(hermesClient: HermesClient, pythContractAddress: string, grpcEndpoint: string, logger: Logger, mnemonic: string, chainConfig?: Partial<InjectiveConfig>);
28
- private injectiveAddress;
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,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAW7C,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAyB9B,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,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AACF,qBAAa,oBAAqB,YAAW,YAAY;IAMrD,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,MAAM;IARhB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,OAAO,CAAwB;gBAG7B,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;IAWxC,OAAO,CAAC,gBAAgB;YAIV,mBAAmB;IAkE3B,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAa1D,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;CAiEjB"}
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
- wallet;
48
+ mnemonic;
47
49
  chainConfig;
48
- account = null;
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.wallet = sdk_ts_1.PrivateKey.fromMnemonic(mnemonic);
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
- injectiveAddress() {
62
- return this.wallet.toBech32();
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.account ??= await chainGrpcAuthApi.fetchAccount(this.injectiveAddress());
68
- const { txRaw: simulateTxRaw } = (0, sdk_ts_1.createTransactionFromMsg)({
69
- sequence: this.account.baseAccount.sequence,
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: this.account.baseAccount.sequence,
95
- accountNumber: this.account.baseAccount.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: this.wallet.toPublicKey().toBase64(),
86
+ fee: await this.getStdFee(msg, index),
87
+ pubKey: wallet.toPublicKey().toBase64(),
100
88
  });
101
- const sig = await this.wallet.sign(Buffer.from(signBytes));
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 txService.broadcast(txRaw);
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
- // We need to fetch the account details again.
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
- let priceFeedUpdateObject;
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
- // get the latest VAAs for updatePriceFeed and then push them
138
- priceFeedUpdateObject = await this.getPriceFeedUpdateObject(priceIds);
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
- this.logger.error(err, "Error fetching the latest vaas to push");
142
- return;
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
- let updateFeeQueryResponse;
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: priceFeedUpdateObject.update_price_feeds.data,
213
+ vaas,
150
214
  },
151
215
  })).toString("base64"));
152
216
  const json = Buffer.from(data).toString();
153
- updateFeeQueryResponse = JSON.parse(json);
217
+ return JSON.parse(json);
154
218
  }
155
219
  catch (err) {
156
- this.logger.error(err, "Error fetching update fee");
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;
@@ -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
@@ -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;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,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"}
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"}