@haven-fi/solauto-sdk 1.0.687 → 1.0.688

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.
@@ -25,8 +25,8 @@ class ClientTransactionsManager extends transactionsManager_1.TransactionsManage
25
25
  ];
26
26
  if (txs.find((x) => x.oracleInteractor) && switchboardMints.length) {
27
27
  this.txHandler.log("Requires oracle update(s)...");
28
- const txs = switchboardMints.map((x) => new types_1.TransactionItem(async () => (0, utils_1.buildSwbSubmitResponseTx)(this.txHandler.connection, this.txHandler.signer, x), this.updateOracleTxName));
29
- txs.unshift(...txs);
28
+ const oracleTxs = switchboardMints.map((x) => new types_1.TransactionItem(async () => await (0, utils_1.buildSwbSubmitResponseTx)(this.txHandler.connection, this.txHandler.signer, x), this.updateOracleTxName));
29
+ txs.unshift(...oracleTxs);
30
30
  }
31
31
  }
32
32
  async addChoreTxs(txs, updateLutTx) {
@@ -260,7 +260,9 @@ class TransactionsManager {
260
260
  }
261
261
  else {
262
262
  await Promise.all(itemSets.map((itemSet) => itemSet.reset()));
263
- await Promise.all(itemSets.map((itemSet) => itemSet.refetchAll(attemptNum, prevError)));
263
+ for (const itemSet of itemSets) {
264
+ await itemSet.refetchAll(attemptNum, prevError);
265
+ }
264
266
  }
265
267
  const newItemSets = await this.assembleTransactionSets(currentIndex !== undefined
266
268
  ? [
@@ -21,4 +21,5 @@ export declare function toEnumValue<E extends object>(enumObj: E, value: number)
21
21
  export declare function customRpcCall(umi: Umi, method: string, params?: any): Promise<any>;
22
22
  export declare function u16ToArrayBufferLE(value: number): Uint8Array;
23
23
  export declare function validPubkey(pubkey?: PublicKey | UmiPublicKey | string): boolean;
24
+ export declare function createRecord<T>(keys: string[], values: T[]): Record<string, T>;
24
25
  //# sourceMappingURL=generalUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generalUtils.d.ts","sourceRoot":"","sources":["../../src/utils/generalUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAa,GAAG,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACtG,OAAO,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAErD,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,UAErD;AAED,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,UAE3D;AAED,wBAAgB,UAAU,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAI/C;AAED,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAErD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAW1D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,yBAQ/C;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAMlE;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,SAAS,GACZ,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAU1E;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAS1D;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,KAAK,CAAC,CAAC;AAEjE,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,EAAE,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,EACvD,OAAO,GAAE,MAAU,EACnB,KAAK,GAAE,MAAY,EACnB,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC,CAAC,CAAC,CA8BZ;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC1C,OAAO,EAAE,CAAC,EACV,KAAK,EAAE,MAAM,GACZ,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAUxB;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,gBAuBzE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAU5D;AAED,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,WAErE"}
1
+ {"version":3,"file":"generalUtils.d.ts","sourceRoot":"","sources":["../../src/utils/generalUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,eAAe,EAEf,GAAG,EACH,SAAS,IAAI,YAAY,EAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAErD,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,UAErD;AAED,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,UAE3D;AAED,wBAAgB,UAAU,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAI/C;AAED,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAErD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAW1D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,yBAQ/C;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAMlE;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,SAAS,GACZ,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAU1E;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAS1D;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,KAAK,CAAC,CAAC;AAEjE,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,EAAE,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,EACvD,OAAO,GAAE,MAAU,EACnB,KAAK,GAAE,MAAY,EACnB,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC,CAAC,CAAC,CA8BZ;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC1C,OAAO,EAAE,CAAC,EACV,KAAK,EAAE,MAAM,GACZ,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAUxB;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,gBAuBzE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAU5D;AAED,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,WAErE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAI9E"}
@@ -22,6 +22,7 @@ exports.toEnumValue = toEnumValue;
22
22
  exports.customRpcCall = customRpcCall;
23
23
  exports.u16ToArrayBufferLE = u16ToArrayBufferLE;
24
24
  exports.validPubkey = validPubkey;
25
+ exports.createRecord = createRecord;
25
26
  const axios_1 = __importDefault(require("axios"));
26
27
  const web3_js_1 = require("@solana/web3.js");
27
28
  const umi_1 = require("@metaplex-foundation/umi");
@@ -173,3 +174,6 @@ function u16ToArrayBufferLE(value) {
173
174
  function validPubkey(pubkey) {
174
175
  return Boolean(pubkey) && pubkey.toString() !== web3_js_1.PublicKey.default.toString();
175
176
  }
177
+ function createRecord(keys, values) {
178
+ return Object.fromEntries(zip(keys, values).map(([k, v]) => [k.toString(), v]));
179
+ }
@@ -6,9 +6,9 @@ interface PriceResult {
6
6
  emaPrice?: number;
7
7
  }
8
8
  export declare function fetchTokenPrices(mints: PublicKey[], priceType?: PriceType): Promise<number[]>;
9
- export declare function getPythPrices(mints: PublicKey[], priceType: PriceType): Promise<PriceResult[]>;
10
- export declare function getSwitchboardPrices(mints: PublicKey[]): Promise<PriceResult[]>;
11
- export declare function getJupTokenPrices(mints: PublicKey[]): Promise<PriceResult[]>;
9
+ export declare function getPythPrices(mints: PublicKey[]): Promise<Record<string, PriceResult>>;
10
+ export declare function getSwitchboardPrices(mints: PublicKey[]): Promise<Record<string, PriceResult>>;
11
+ export declare function getJupTokenPrices(mints: PublicKey[]): Promise<Record<string, PriceResult>>;
12
12
  export declare function safeGetPrice(mint: PublicKey | UmiPublicKey | string | undefined, priceType?: PriceType): number | undefined;
13
13
  export {};
14
14
  //# sourceMappingURL=priceUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"priceUtils.d.ts","sourceRoot":"","sources":["../../src/utils/priceUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAerE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,UAAU,WAAW;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,EAAE,EAClB,SAAS,GAAE,SAA8B,GACxC,OAAO,CAAC,MAAM,EAAE,CAAC,CAoDnB;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,EAAE,EAClB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,WAAW,EAAE,CAAC,CA+CxB;AAkBD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,WAAW,EAAE,CAAC,CA0DxB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,WAAW,EAAE,CAAC,CAgBxB;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,EACnD,SAAS,GAAE,SAA8B,GACxC,MAAM,GAAG,SAAS,CAQpB"}
1
+ {"version":3,"file":"priceUtils.d.ts","sourceRoot":"","sources":["../../src/utils/priceUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAerE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,UAAU,WAAW;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,EAAE,EAClB,SAAS,GAAE,SAA8B,GACxC,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDnB;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAkDtC;AAkBD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CA+CtC;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAiBtC;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,EACnD,SAAS,GAAE,SAA8B,GACxC,MAAM,GAAG,SAAS,CAQpB"}
@@ -37,42 +37,42 @@ const jupiterUtils_1 = require("./jupiterUtils");
37
37
  const generated_1 = require("../generated");
38
38
  async function fetchTokenPrices(mints, priceType = generated_1.PriceType.Realtime) {
39
39
  const currentTime = (0, generalUtils_1.currentUnixSeconds)();
40
- if (!mints.some((mint) => !(mint.toString() in constants_1.PRICES) ||
41
- currentTime - constants_1.PRICES[mint.toString()].time > 3)) {
42
- return mints.map((mint) => {
43
- const priceData = constants_1.PRICES[mint.toString()];
44
- return priceType === generated_1.PriceType.Ema
45
- ? priceData.emaPrice
46
- : priceData.realtimePrice;
47
- });
48
- }
49
- const pythMints = mints.filter((x) => x.toString() in constants_1.PYTH_PRICE_FEED_IDS);
50
- const switchboardMints = mints.filter((x) => x.toString() in Object.keys(constants_1.SWITCHBOARD_PRICE_FEED_IDS));
51
- const otherMints = mints.filter((x) => !pythMints.includes(x) && !switchboardMints.includes(x));
52
- const [pythData, switchboardData, jupData] = await Promise.all([
53
- (0, generalUtils_1.zip)(pythMints, await getPythPrices(pythMints, priceType)),
54
- (0, generalUtils_1.zip)(switchboardMints, await getSwitchboardPrices(switchboardMints)),
55
- (0, generalUtils_1.zip)(otherMints, await getJupTokenPrices(otherMints)),
56
- ]);
57
- const prices = mints.map((mint) => {
58
- const item = [...pythData, ...switchboardData, ...jupData].find((data) => data[0].equals(mint));
59
- return item ? item[1] : { realtimePrice: 0 };
60
- });
61
- for (var i = 0; i < mints.length; i++) {
62
- const realtimePrice = prices[i].realtimePrice;
63
- constants_1.PRICES[mints[i].toString()] = {
40
+ const mintStrs = mints.map((x) => x.toString());
41
+ const cachedPrices = Object.fromEntries(Object.entries(constants_1.PRICES).filter(([mint, price]) => mintStrs.includes(mint) && currentTime - price.time <= 3));
42
+ const newMints = mintStrs
43
+ .filter((x) => !Object.keys(cachedPrices).includes(x))
44
+ .map((x) => new web3_js_1.PublicKey(x));
45
+ const pythMints = newMints.filter((x) => x.toString() in constants_1.PYTH_PRICE_FEED_IDS);
46
+ const switchboardMints = newMints.filter((x) => x.toString() in Object.keys(constants_1.SWITCHBOARD_PRICE_FEED_IDS));
47
+ const otherMints = newMints.filter((x) => !pythMints.includes(x) && !switchboardMints.includes(x));
48
+ const newPrices = Object.assign({}, ...(await Promise.all([
49
+ getPythPrices(pythMints),
50
+ getSwitchboardPrices(switchboardMints),
51
+ getJupTokenPrices(otherMints),
52
+ ])));
53
+ for (const mint of newMints) {
54
+ const realtimePrice = newPrices[mint.toString()].realtimePrice;
55
+ constants_1.PRICES[mint.toString()] = {
64
56
  realtimePrice,
65
- emaPrice: prices[i].emaPrice ?? realtimePrice,
57
+ emaPrice: newPrices[mint.toString()].emaPrice ?? realtimePrice,
66
58
  time: (0, generalUtils_1.currentUnixSeconds)(),
67
59
  };
68
60
  }
69
- return prices.map((x) => priceType === generated_1.PriceType.Ema
70
- ? (x.emaPrice ?? x.realtimePrice)
71
- : x.realtimePrice);
61
+ const prices = {
62
+ ...constants_1.PRICES,
63
+ ...newPrices,
64
+ };
65
+ return mints.map((x) => {
66
+ const priceResult = prices[x.toString()];
67
+ const realtimePrice = priceResult.realtimePrice;
68
+ return priceType === generated_1.PriceType.Ema
69
+ ? (priceResult.emaPrice ?? realtimePrice)
70
+ : realtimePrice;
71
+ });
72
72
  }
73
- async function getPythPrices(mints, priceType) {
73
+ async function getPythPrices(mints) {
74
74
  if (mints.length === 0) {
75
- return [];
75
+ return {};
76
76
  }
77
77
  const priceFeedIds = mints.map((mint) => constants_1.PYTH_PRICE_FEED_IDS[mint.toString()]);
78
78
  const getReq = async () => await fetch(`https://hermes.pyth.network/v2/updates/price/latest?${priceFeedIds.map((x) => `ids%5B%5D=${x}`).join("&")}`);
@@ -102,7 +102,7 @@ async function getPythPrices(mints, priceType) {
102
102
  });
103
103
  return prices;
104
104
  }, 5, 200);
105
- return prices;
105
+ return (0, generalUtils_1.createRecord)(mints.map((x) => x.toString()), prices);
106
106
  }
107
107
  function getSortedPriceData(prices, mints) {
108
108
  const sortedPrices = {};
@@ -116,7 +116,7 @@ function getSortedPriceData(prices, mints) {
116
116
  }
117
117
  async function getSwitchboardPrices(mints) {
118
118
  if (mints.length === 0) {
119
- return [];
119
+ return {};
120
120
  }
121
121
  const { CrossbarClient } = SwbCommon;
122
122
  const crossbar = CrossbarClient.default();
@@ -133,7 +133,7 @@ async function getSwitchboardPrices(mints) {
133
133
  for (const item of resp) {
134
134
  for (const [k, v] of Object.entries(constants_1.SWITCHBOARD_PRICE_FEED_IDS)) {
135
135
  if (item.feedHash === v.feedHash) {
136
- finalMap[k] = Number(item.results[0]);
136
+ finalMap[k] = { realtimePrice: Number(item.results[0]) };
137
137
  }
138
138
  }
139
139
  }
@@ -144,25 +144,21 @@ async function getSwitchboardPrices(mints) {
144
144
  (0, generalUtils_1.consoleLog)("Failed to fetch Switchboard prices after multiple retries");
145
145
  }
146
146
  const missingMints = mints.filter((x) => !prices[x.toString()]);
147
- const jupPrices = (0, generalUtils_1.zip)(missingMints, await getJupTokenPrices(missingMints.map((x) => new web3_js_1.PublicKey(x)))).reduce((acc, [key, value]) => {
148
- acc[key.toString()] = value.realtimePrice;
149
- return acc;
150
- }, {});
151
- return Object.values(getSortedPriceData({ ...prices, ...jupPrices }, mints)).map((x) => {
152
- return { realtimePrice: x };
153
- });
147
+ const jupPrices = await getJupTokenPrices(missingMints.map((x) => new web3_js_1.PublicKey(x)));
148
+ return { ...prices, ...jupPrices };
154
149
  }
155
150
  async function getJupTokenPrices(mints) {
156
151
  if (mints.length == 0) {
157
- return [];
152
+ return {};
158
153
  }
159
154
  const data = getSortedPriceData(await (0, jupiterUtils_1.getJupPriceData)(mints), mints);
160
- const prices = Object.values(data).map((x) => x !== null && typeof x === "object" && "price" in x
161
- ? parseFloat(x.price)
162
- : 0);
163
- return prices.map((x) => {
164
- return { realtimePrice: x };
165
- });
155
+ const prices = Object.fromEntries(Object.entries(data).map(([mint, x]) => [
156
+ mint,
157
+ x !== null && typeof x === "object" && "price" in x
158
+ ? { realtimePrice: parseFloat(x.price) }
159
+ : { realtimePrice: 0 },
160
+ ]));
161
+ return prices;
166
162
  }
167
163
  function safeGetPrice(mint, priceType = generated_1.PriceType.Realtime) {
168
164
  if (mint && mint?.toString() in constants_1.PRICES) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haven-fi/solauto-sdk",
3
- "version": "1.0.687",
3
+ "version": "1.0.688",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "description": "Typescript SDK for the Solauto program on the Solana blockchain",
@@ -45,11 +45,11 @@ export class ClientTransactionsManager extends TransactionsManager<SolautoClient
45
45
 
46
46
  if (txs.find((x) => x.oracleInteractor) && switchboardMints.length) {
47
47
  this.txHandler.log("Requires oracle update(s)...");
48
- const txs = switchboardMints.map(
48
+ const oracleTxs = switchboardMints.map(
49
49
  (x) =>
50
50
  new TransactionItem(
51
51
  async () =>
52
- buildSwbSubmitResponseTx(
52
+ await buildSwbSubmitResponseTx(
53
53
  this.txHandler.connection,
54
54
  this.txHandler.signer,
55
55
  x
@@ -57,7 +57,7 @@ export class ClientTransactionsManager extends TransactionsManager<SolautoClient
57
57
  this.updateOracleTxName
58
58
  )
59
59
  );
60
- txs.unshift(...txs);
60
+ txs.unshift(...oracleTxs);
61
61
  }
62
62
  }
63
63
 
@@ -470,9 +470,9 @@ export class TransactionsManager<T extends TxHandler> {
470
470
  await itemSet.refetchAll(attemptNum, prevError);
471
471
  } else {
472
472
  await Promise.all(itemSets.map((itemSet) => itemSet.reset()));
473
- await Promise.all(
474
- itemSets.map((itemSet) => itemSet.refetchAll(attemptNum, prevError))
475
- );
473
+ for (const itemSet of itemSets) {
474
+ await itemSet.refetchAll(attemptNum, prevError);
475
+ }
476
476
  }
477
477
 
478
478
  const newItemSets = await this.assembleTransactionSets(
@@ -1,6 +1,11 @@
1
1
  import axios from "axios";
2
2
  import { PublicKey } from "@solana/web3.js";
3
- import { MaybeRpcAccount, publicKey, Umi, PublicKey as UmiPublicKey } from "@metaplex-foundation/umi";
3
+ import {
4
+ MaybeRpcAccount,
5
+ publicKey,
6
+ Umi,
7
+ PublicKey as UmiPublicKey,
8
+ } from "@metaplex-foundation/umi";
4
9
  import { TOKEN_INFO, TokenInfo } from "../constants";
5
10
 
6
11
  export function buildHeliusApiUrl(heliusApiKey: string) {
@@ -199,4 +204,10 @@ export function u16ToArrayBufferLE(value: number): Uint8Array {
199
204
 
200
205
  export function validPubkey(pubkey?: PublicKey | UmiPublicKey | string) {
201
206
  return Boolean(pubkey) && pubkey!.toString() !== PublicKey.default.toString();
202
- }
207
+ }
208
+
209
+ export function createRecord<T>(keys: string[], values: T[]): Record<string, T> {
210
+ return Object.fromEntries(
211
+ zip(keys, values).map(([k, v]) => [k.toString(), v])
212
+ );
213
+ }
@@ -9,9 +9,9 @@ import {
9
9
  import { fromBaseUnit, toBaseUnit } from "./numberUtils";
10
10
  import {
11
11
  consoleLog,
12
+ createRecord,
12
13
  currentUnixSeconds,
13
14
  retryWithExponentialBackoff,
14
- zip,
15
15
  } from "./generalUtils";
16
16
  import { getJupPriceData } from "./jupiterUtils";
17
17
  import { PriceType } from "../generated";
@@ -26,64 +26,61 @@ export async function fetchTokenPrices(
26
26
  priceType: PriceType = PriceType.Realtime
27
27
  ): Promise<number[]> {
28
28
  const currentTime = currentUnixSeconds();
29
- if (
30
- !mints.some(
31
- (mint) =>
32
- !(mint.toString() in PRICES) ||
33
- currentTime - PRICES[mint.toString()].time > 3
29
+ const mintStrs = mints.map((x) => x.toString());
30
+ const cachedPrices: Record<string, PriceResult> = Object.fromEntries(
31
+ Object.entries(PRICES).filter(
32
+ ([mint, price]) =>
33
+ mintStrs.includes(mint) && currentTime - price.time <= 3
34
34
  )
35
- ) {
36
- return mints.map((mint) => {
37
- const priceData = PRICES[mint.toString()];
38
- return priceType === PriceType.Ema
39
- ? priceData.emaPrice
40
- : priceData.realtimePrice;
41
- });
42
- }
35
+ );
43
36
 
44
- const pythMints = mints.filter((x) => x.toString() in PYTH_PRICE_FEED_IDS);
45
- const switchboardMints = mints.filter(
37
+ const newMints = mintStrs
38
+ .filter((x) => !Object.keys(cachedPrices).includes(x))
39
+ .map((x) => new PublicKey(x));
40
+ const pythMints = newMints.filter((x) => x.toString() in PYTH_PRICE_FEED_IDS);
41
+ const switchboardMints = newMints.filter(
46
42
  (x) => x.toString() in Object.keys(SWITCHBOARD_PRICE_FEED_IDS)
47
43
  );
48
- const otherMints = mints.filter(
44
+ const otherMints = newMints.filter(
49
45
  (x) => !pythMints.includes(x) && !switchboardMints.includes(x)
50
46
  );
47
+ const newPrices: Record<string, PriceResult> = Object.assign(
48
+ {},
49
+ ...(await Promise.all([
50
+ getPythPrices(pythMints),
51
+ getSwitchboardPrices(switchboardMints),
52
+ getJupTokenPrices(otherMints),
53
+ ]))
54
+ );
51
55
 
52
- const [pythData, switchboardData, jupData] = await Promise.all([
53
- zip(pythMints, await getPythPrices(pythMints, priceType)),
54
- zip(switchboardMints, await getSwitchboardPrices(switchboardMints)),
55
- zip(otherMints, await getJupTokenPrices(otherMints)),
56
- ]);
57
-
58
- const prices = mints.map((mint) => {
59
- const item = [...pythData, ...switchboardData, ...jupData].find((data) =>
60
- data[0].equals(mint)
61
- );
62
- return item ? item[1] : { realtimePrice: 0 };
63
- });
64
-
65
- for (var i = 0; i < mints.length; i++) {
66
- const realtimePrice = prices[i].realtimePrice;
67
- PRICES[mints[i].toString()] = {
56
+ for (const mint of newMints) {
57
+ const realtimePrice = newPrices[mint.toString()].realtimePrice;
58
+ PRICES[mint.toString()] = {
68
59
  realtimePrice,
69
- emaPrice: prices[i].emaPrice ?? realtimePrice,
60
+ emaPrice: newPrices[mint.toString()].emaPrice ?? realtimePrice,
70
61
  time: currentUnixSeconds(),
71
62
  };
72
63
  }
73
64
 
74
- return prices.map((x) =>
75
- priceType === PriceType.Ema
76
- ? (x.emaPrice ?? x.realtimePrice)
77
- : x.realtimePrice
78
- );
65
+ const prices: Record<string, PriceResult> = {
66
+ ...PRICES,
67
+ ...newPrices,
68
+ };
69
+
70
+ return mints.map((x) => {
71
+ const priceResult = prices[x.toString()];
72
+ const realtimePrice = priceResult.realtimePrice;
73
+ return priceType === PriceType.Ema
74
+ ? (priceResult.emaPrice ?? realtimePrice)
75
+ : realtimePrice;
76
+ });
79
77
  }
80
78
 
81
79
  export async function getPythPrices(
82
- mints: PublicKey[],
83
- priceType: PriceType
84
- ): Promise<PriceResult[]> {
80
+ mints: PublicKey[]
81
+ ): Promise<Record<string, PriceResult>> {
85
82
  if (mints.length === 0) {
86
- return [];
83
+ return {};
87
84
  }
88
85
 
89
86
  const priceFeedIds = mints.map(
@@ -127,7 +124,10 @@ export async function getPythPrices(
127
124
  200
128
125
  );
129
126
 
130
- return prices;
127
+ return createRecord(
128
+ mints.map((x) => x.toString()),
129
+ prices
130
+ );
131
131
  }
132
132
 
133
133
  function getSortedPriceData(
@@ -148,15 +148,15 @@ function getSortedPriceData(
148
148
 
149
149
  export async function getSwitchboardPrices(
150
150
  mints: PublicKey[]
151
- ): Promise<PriceResult[]> {
151
+ ): Promise<Record<string, PriceResult>> {
152
152
  if (mints.length === 0) {
153
- return [];
153
+ return {};
154
154
  }
155
155
 
156
156
  const { CrossbarClient } = SwbCommon;
157
157
  const crossbar = CrossbarClient.default();
158
158
 
159
- let prices: Record<string, number> = {};
159
+ let prices: Record<string, PriceResult> = {};
160
160
  try {
161
161
  prices = await retryWithExponentialBackoff(
162
162
  async () => {
@@ -172,11 +172,11 @@ export async function getSwitchboardPrices(
172
172
  throw new Error("Unable to fetch Switchboard prices");
173
173
  }
174
174
 
175
- const finalMap: Record<string, number> = {};
175
+ const finalMap: Record<string, PriceResult> = {};
176
176
  for (const item of resp) {
177
177
  for (const [k, v] of Object.entries(SWITCHBOARD_PRICE_FEED_IDS)) {
178
178
  if (item.feedHash === v.feedHash) {
179
- finalMap[k] = Number(item.results[0]);
179
+ finalMap[k] = { realtimePrice: Number(item.results[0]) };
180
180
  }
181
181
  }
182
182
  }
@@ -190,42 +190,32 @@ export async function getSwitchboardPrices(
190
190
  }
191
191
 
192
192
  const missingMints = mints.filter((x) => !prices[x.toString()]);
193
- const jupPrices = zip(
194
- missingMints,
195
- await getJupTokenPrices(missingMints.map((x) => new PublicKey(x)))
196
- ).reduce(
197
- (acc, [key, value]) => {
198
- acc[key.toString()] = value.realtimePrice;
199
- return acc;
200
- },
201
- {} as Record<string, number>
193
+ const jupPrices = await getJupTokenPrices(
194
+ missingMints.map((x) => new PublicKey(x))
202
195
  );
203
196
 
204
- return Object.values(
205
- getSortedPriceData({ ...prices, ...jupPrices }, mints)
206
- ).map((x) => {
207
- return { realtimePrice: x };
208
- });
197
+ return { ...prices, ...jupPrices };
209
198
  }
210
199
 
211
200
  export async function getJupTokenPrices(
212
201
  mints: PublicKey[]
213
- ): Promise<PriceResult[]> {
202
+ ): Promise<Record<string, PriceResult>> {
214
203
  if (mints.length == 0) {
215
- return [];
204
+ return {};
216
205
  }
217
206
 
218
207
  const data = getSortedPriceData(await getJupPriceData(mints), mints);
219
208
 
220
- const prices = Object.values(data).map((x) =>
221
- x !== null && typeof x === "object" && "price" in x
222
- ? parseFloat(x.price as string)
223
- : 0
209
+ const prices: Record<string, PriceResult> = Object.fromEntries(
210
+ Object.entries(data).map(([mint, x]) => [
211
+ mint,
212
+ x !== null && typeof x === "object" && "price" in x
213
+ ? { realtimePrice: parseFloat(x.price as string) }
214
+ : { realtimePrice: 0 },
215
+ ])
224
216
  );
225
217
 
226
- return prices.map((x) => {
227
- return { realtimePrice: x };
228
- });
218
+ return prices;
229
219
  }
230
220
 
231
221
  export function safeGetPrice(