@haven-fi/solauto-sdk 1.0.825 → 1.0.828

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.
@@ -4,4 +4,5 @@ export declare const SOLAUTO_FEES_WALLET: PublicKey;
4
4
  export declare const SOLAUTO_MANAGER: PublicKey;
5
5
  export declare const LOCAL_IRONFORGE_API_URL: string;
6
6
  export declare const BASIS_POINTS = 10000;
7
+ export declare const CROSSBAR_URL = "https://crossbar.0.xyz/";
7
8
  //# sourceMappingURL=generalConstants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generalConstants.d.ts","sourceRoot":"","sources":["../../src/constants/generalConstants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,mBAAmB,WAAgE,CAAC;AACjG,eAAO,MAAM,eAAe,WAA+D,CAAC;AAE5F,eAAO,MAAM,uBAAuB,QAAuD,CAAC;AAE5F,eAAO,MAAM,YAAY,QAAQ,CAAC"}
1
+ {"version":3,"file":"generalConstants.d.ts","sourceRoot":"","sources":["../../src/constants/generalConstants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,mBAAmB,WAAgE,CAAC;AACjG,eAAO,MAAM,eAAe,WAA+D,CAAC;AAE5F,eAAO,MAAM,uBAAuB,QAAuD,CAAC;AAE5F,eAAO,MAAM,YAAY,QAAQ,CAAC;AAElC,eAAO,MAAM,YAAY,4BAA4B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BASIS_POINTS = exports.LOCAL_IRONFORGE_API_URL = exports.SOLAUTO_MANAGER = exports.SOLAUTO_FEES_WALLET = exports.USD_DECIMALS = void 0;
3
+ exports.CROSSBAR_URL = exports.BASIS_POINTS = exports.LOCAL_IRONFORGE_API_URL = exports.SOLAUTO_MANAGER = exports.SOLAUTO_FEES_WALLET = exports.USD_DECIMALS = void 0;
4
4
  const web3_js_1 = require("@solana/web3.js");
5
5
  const utils_1 = require("../utils");
6
6
  exports.USD_DECIMALS = 9;
@@ -8,3 +8,4 @@ exports.SOLAUTO_FEES_WALLET = new web3_js_1.PublicKey("AprYCPiVeKMCgjQ2ZufwChMzv
8
8
  exports.SOLAUTO_MANAGER = new web3_js_1.PublicKey("MNGRcX4nc7quPdzBbNKJ4ScK5EE73JnwJVGxuJXhHCY");
9
9
  exports.LOCAL_IRONFORGE_API_URL = (0, utils_1.buildIronforgeApiUrl)(process.env.IRONFORGE_API_KEY);
10
10
  exports.BASIS_POINTS = 10000;
11
+ exports.CROSSBAR_URL = "https://crossbar.0.xyz/";
@@ -1 +1 @@
1
- {"version":3,"file":"jitoUtils.d.ts","sourceRoot":"","sources":["../../src/utils/jitoUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,MAAM,EACN,kBAAkB,EAClB,GAAG,EAEH,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAiBlE,wBAAgB,mBAAmB,IAAI,SAAS,CAG/C;AAiGD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB;;;;IAkB/D;AAqHD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,kBAAkB,EAAE,EAClC,MAAM,CAAC,EAAE,kBAAkB,EAC3B,kBAAkB,GAAE,kBAA2C,EAC/D,cAAc,CAAC,EAAE,MAAM,IAAI,EAC3B,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CA6G/B"}
1
+ {"version":3,"file":"jitoUtils.d.ts","sourceRoot":"","sources":["../../src/utils/jitoUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,MAAM,EACN,kBAAkB,EAClB,GAAG,EAEH,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAiBlE,wBAAgB,mBAAmB,IAAI,SAAS,CAG/C;AAiGD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB;;;;IAkB/D;AAyHD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,kBAAkB,EAAE,EAClC,MAAM,CAAC,EAAE,kBAAkB,EAC3B,kBAAkB,GAAE,kBAA2C,EAC/D,cAAc,CAAC,EAAE,MAAM,IAAI,EAC3B,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CA6G/B"}
@@ -142,13 +142,14 @@ async function pollBundleStatus(umi, bundleId, interval = 1000, timeout = 40000)
142
142
  if (statuses?.value?.length > 0) {
143
143
  (0, generalUtils_1.consoleLog)("Statuses:", statuses);
144
144
  const status = statuses.value[0].confirmation_status;
145
- if (status === "confirmed") {
145
+ if (status === "confirmed" || status === "finalized") {
146
146
  return statuses.value[0].transactions;
147
147
  }
148
148
  const err = statuses.value[0].err;
149
- if (err) {
149
+ // Jito reports a successful bundle as err: { Ok: null }
150
+ if (err && !("Ok" in err && err.Ok === null)) {
150
151
  (0, generalUtils_1.consoleLog)("Jito bundle err:", JSON.stringify(err, null, 2));
151
- throw new Error(err);
152
+ throw new Error(JSON.stringify(err));
152
153
  }
153
154
  }
154
155
  }
@@ -168,11 +169,12 @@ async function sendJitoBundle(umi, transactions) {
168
169
  throw e;
169
170
  }
170
171
  }
171
- if (resp.error?.message === "All providers failed") {
172
- throw new Error(resp.error.responses[0].response.error.message);
172
+ if (resp.error?.responses?.length) {
173
+ const inner = resp.error.responses[0].response?.error;
174
+ throw new Error(`${resp.error.message}: ${inner ? (inner.message ?? JSON.stringify(inner)) : "unknown"}`);
173
175
  }
174
176
  else if (resp.error) {
175
- throw new Error(resp.error);
177
+ throw new Error(resp.error.message ?? JSON.stringify(resp.error));
176
178
  }
177
179
  const bundleId = resp;
178
180
  (0, generalUtils_1.consoleLog)("Bundle ID:", bundleId);
@@ -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;AAgBrE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,UAAU,WAAW;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,EAAE,EAClB,SAAS,GAAE,SAA8B,EACzC,SAAS,CAAC,EAAE,SAAS,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CA8CnB;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAuDtC;AAkBD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAkDtC;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAsBtC;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,EACnD,SAAS,GAAE,SAA8B,EACzC,SAAS,CAAC,EAAE,SAAS,GACpB,MAAM,GAAG,SAAS,CAyBpB"}
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;AAiBrE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,UAAU,WAAW;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,EAAE,EAClB,SAAS,GAAE,SAA8B,EACzC,SAAS,CAAC,EAAE,SAAS,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CA8CnB;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAuDtC;AAkBD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAsDtC;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAsBtC;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,EACnD,SAAS,GAAE,SAA8B,EACzC,SAAS,CAAC,EAAE,SAAS,GACpB,MAAM,GAAG,SAAS,CAyBpB"}
@@ -128,26 +128,29 @@ async function getSwitchboardPrices(mints) {
128
128
  return {};
129
129
  }
130
130
  const { CrossbarClient } = SwbCommon;
131
- const crossbar = new CrossbarClient("https://crossbar.0.xyz/");
131
+ const crossbar = new CrossbarClient(constants_1.CROSSBAR_URL);
132
132
  let prices = {};
133
133
  try {
134
134
  prices = await (0, generalUtils_1.retryWithExponentialBackoff)(async () => {
135
- const resp = await crossbar.simulateFeeds(mints.map((x) => constants_1.SWITCHBOARD_PRICE_FEED_IDS[x.toString()].feedHash));
136
- const data = resp.flatMap((x) => x.results[0]);
137
- if (data.filter((x) => !x || isNaN(Number(x)) || Number(x) <= 0).length >
138
- 0) {
139
- throw new Error("Unable to fetch Switchboard prices");
140
- }
135
+ const mintByFeed = new Map(mints.map((mint) => [
136
+ constants_1.SWITCHBOARD_PRICE_FEED_IDS[mint.toString()].feedId,
137
+ mint.toString(),
138
+ ]));
139
+ const resp = await crossbar.simulateSolanaFeeds("mainnet", Array.from(mintByFeed.keys()));
141
140
  const finalMap = {};
142
141
  for (const item of resp) {
143
- for (const [k, v] of Object.entries(constants_1.SWITCHBOARD_PRICE_FEED_IDS)) {
144
- if (item.feedHash === v.feedHash) {
145
- const price = Number(item.results[0]);
146
- finalMap[k] = {
147
- realtimePrice: price,
148
- };
149
- }
142
+ const mint = mintByFeed.get(item.feed);
143
+ // Crossbar currently returns the aggregate as `result`; retain `results[0]` for
144
+ // compatibility with the published SDK response type.
145
+ const result = "result" in item ? item.result : item.results[0];
146
+ const price = Number(result);
147
+ if (!mint || !Number.isFinite(price) || price <= 0) {
148
+ throw new Error("Unable to fetch Switchboard prices");
150
149
  }
150
+ finalMap[mint] = { realtimePrice: price };
151
+ }
152
+ if (Object.keys(finalMap).length !== mintByFeed.size) {
153
+ throw new Error("Unable to fetch all Switchboard prices");
151
154
  }
152
155
  return finalMap;
153
156
  }, 2, 350);
@@ -2,9 +2,10 @@ import { Connection, PublicKey } from "@solana/web3.js";
2
2
  import { Signer } from "@metaplex-foundation/umi";
3
3
  import * as OnDemand from "@switchboard-xyz/on-demand";
4
4
  import { TransactionItemInputs } from "../types";
5
+ import { CrossbarClient } from "@switchboard-xyz/common";
5
6
  import { SolautoClient, TransactionItem } from "../services";
6
7
  export declare function getPullFeed(conn: Connection, mint: PublicKey, wallet?: PublicKey): Promise<{
7
- gateway: OnDemand.Gateway;
8
+ crossbar: CrossbarClient;
8
9
  feed: OnDemand.PullFeed;
9
10
  }>;
10
11
  export declare function buildSwbSubmitResponseTx(conn: Connection, signer: Signer, mint: PublicKey): Promise<TransactionItemInputs | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"switchboardUtils.d.ts","sourceRoot":"","sources":["../../src/utils/switchboardUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EAGV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,MAAM,EAAsB,MAAM,0BAA0B,CAAC;AAGtE,OAAO,KAAK,QAAQ,MAAM,4BAA4B,CAAC;AAOvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAQjD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7D,wBAAsB,WAAW,CAC/B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,SAAS,EACf,MAAM,CAAC,EAAE,SAAS;;;GAkCnB;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAsE5C;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EAAE,CAAC,CAuB/D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,WAEzD;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,eAAe,EAAE,iBAkCvB"}
1
+ {"version":3,"file":"switchboardUtils.d.ts","sourceRoot":"","sources":["../../src/utils/switchboardUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EAGV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,MAAM,EAAsB,MAAM,0BAA0B,CAAC;AAGtE,OAAO,KAAK,QAAQ,MAAM,4BAA4B,CAAC;AAQvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAOjD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7D,wBAAsB,WAAW,CAC/B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,SAAS,EACf,MAAM,CAAC,EAAE,SAAS;;;GAgCnB;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAyE5C;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EAAE,CAAC,CAuB/D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,WAEzD;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,eAAe,EAAE,iBAkCvB"}
@@ -56,26 +56,22 @@ async function getPullFeed(conn, mint, wallet) {
56
56
  };
57
57
  const provider = new anchor_1.AnchorProvider(conn, dummyWallet, anchor_1.AnchorProvider.defaultOptions());
58
58
  (0, generalUtils_1.consoleLog)("Pulling SWB program...");
59
- const { PullFeed, Queue, ON_DEMAND_MAINNET_PID } = OnDemand;
59
+ const { PullFeed, ON_DEMAND_MAINNET_PID } = OnDemand;
60
60
  const sbProgram = await anchor_1.Program.at(ON_DEMAND_MAINNET_PID, provider);
61
- const crossbar = new common_1.CrossbarClient("https://integrator-crossbar.mrgn.app/");
62
- const queue = await Queue.loadDefault(sbProgram);
63
- const gateway = await queue.fetchGatewayFromCrossbar(crossbar);
61
+ const crossbar = new common_1.CrossbarClient(constants_1.CROSSBAR_URL);
64
62
  (0, generalUtils_1.consoleLog)("Pulled SWB program!");
65
63
  (0, generalUtils_1.consoleLog)("Feed id:", constants_1.SWITCHBOARD_PRICE_FEED_IDS[mint.toString()].feedId);
66
64
  return {
67
- gateway,
65
+ crossbar,
68
66
  feed: new PullFeed(sbProgram, new web3_js_1.PublicKey(constants_1.SWITCHBOARD_PRICE_FEED_IDS[mint.toString()].feedId)),
69
67
  };
70
68
  }
71
69
  async function buildSwbSubmitResponseTx(conn, signer, mint) {
72
- const { feed, gateway } = await getPullFeed(conn, mint, (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(signer.publicKey));
70
+ const { feed, crossbar } = await getPullFeed(conn, mint, (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(signer.publicKey));
73
71
  (0, generalUtils_1.consoleLog)("Fetching crank IX...");
74
- const [pullIxs, responses] = await (0, generalUtils_1.retryWithExponentialBackoff)(async () => {
72
+ const [pullIxs, responses, , luts] = await (0, generalUtils_1.retryWithExponentialBackoff)(async () => {
75
73
  const res = await feed.fetchUpdateIx({
76
- gateway: gateway.endpoint(),
77
- chain: "solana",
78
- network: "mainnet-beta",
74
+ crossbarClient: crossbar,
79
75
  });
80
76
  if (!res[1] || !res[1][0].value) {
81
77
  throw new Error("Unable to fetch Switchboard pull IX");
@@ -113,9 +109,12 @@ async function buildSwbSubmitResponseTx(conn, signer, mint) {
113
109
  (0, generalUtils_1.consoleLog)("Returning SWB transaction data...");
114
110
  return {
115
111
  tx: (0, umi_1.transactionBuilder)(pullIxs.map((x) => (0, solanaUtils_1.getWrappedInstruction)(signer, x))),
116
- lookupTableAddresses: responses
117
- .filter((x) => Boolean(x.oracle.lut?.key))
118
- .map((x) => x.oracle.lut.key.toString()),
112
+ lookupTableAddresses: Array.from(new Set([
113
+ ...luts.map((x) => x.key.toString()),
114
+ ...responses
115
+ .filter((x) => Boolean(x.oracle.lut?.key))
116
+ .map((x) => x.oracle.lut.key.toString()),
117
+ ])),
119
118
  orderPrio: -2,
120
119
  };
121
120
  }
@@ -1,4 +1,5 @@
1
1
  import { Keypair, PublicKey } from "@solana/web3.js";
2
+ import { NATIVE_MINT } from "@solana/spl-token";
2
3
  import { createSignerFromKeypair, publicKey, signerIdentity } from "@metaplex-foundation/umi";
3
4
  import { fromWeb3JsKeypair } from "@metaplex-foundation/umi-web3js-adapters";
4
5
  import {
@@ -118,6 +119,20 @@ async function refreshAll() {
118
119
  }
119
120
  }
120
121
 
122
+ // Crank a Switchboard pull feed for a single mint, as one standalone tx (no bundle).
123
+ // Usage: npx ts-node local/txSandbox.ts [mint]
124
+ // mint defaults to SOL; accepts a raw mint address or a shorthand below.
125
+ const MINT_SHORTHANDS: Record<string, string> = {
126
+ sol: NATIVE_MINT.toString(),
127
+ jitosol: JITO_SOL,
128
+ };
129
+
130
+ function resolveMint(arg?: string): PublicKey {
131
+ if (!arg) return NATIVE_MINT;
132
+ const shorthand = MINT_SHORTHANDS[arg.toLowerCase()];
133
+ return new PublicKey(shorthand ?? arg);
134
+ }
135
+
121
136
  async function testSwbOracleUpdate() {
122
137
  (globalThis as any).SHOW_LOGS = true;
123
138
 
@@ -128,8 +143,8 @@ async function testSwbOracleUpdate() {
128
143
  );
129
144
  umiLocal = umiLocal.use(signerIdentity(signer));
130
145
 
131
- const mint = new PublicKey(JITO_SOL);
132
- console.log("Building SWB oracle update tx for JitoSOL...");
146
+ const mint = resolveMint(process.argv[2]);
147
+ console.log("Building SWB oracle update tx for mint:", mint.toString());
133
148
 
134
149
  const result = await buildSwbSubmitResponseTx(conn, signer, mint);
135
150
  if (!result) {
@@ -139,6 +154,7 @@ async function testSwbOracleUpdate() {
139
154
 
140
155
  console.log("Instructions count:", result.tx.getInstructions().length);
141
156
  console.log("Lookup tables:", result.lookupTableAddresses);
157
+ console.log("Transaction size:", result.tx.getTransactionSize(umiLocal));
142
158
 
143
159
  console.log("Sending transaction...");
144
160
  const sig = await sendSingleOptimizedTransaction(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haven-fi/solauto-sdk",
3
- "version": "1.0.825",
3
+ "version": "1.0.828",
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",
@@ -20,8 +20,8 @@
20
20
  "@metaplex-foundation/umi-web3js-adapters": "^0.9.1",
21
21
  "@solana/spl-token": "^0.4.0",
22
22
  "@solana/web3.js": "=1.98.2",
23
- "@switchboard-xyz/common": "=3.4.1",
24
- "@switchboard-xyz/on-demand": "=2.17.4",
23
+ "@switchboard-xyz/common": "=5.8.5",
24
+ "@switchboard-xyz/on-demand": "=3.10.6",
25
25
  "axios": "^1.7.8",
26
26
  "big.js": "^6.2.2",
27
27
  "bs58": "^5.0.0",
@@ -8,3 +8,5 @@ export const SOLAUTO_MANAGER = new PublicKey("MNGRcX4nc7quPdzBbNKJ4ScK5EE73JnwJV
8
8
  export const LOCAL_IRONFORGE_API_URL = buildIronforgeApiUrl(process.env.IRONFORGE_API_KEY!);
9
9
 
10
10
  export const BASIS_POINTS = 10000;
11
+
12
+ export const CROSSBAR_URL = "https://crossbar.0.xyz/";
@@ -224,13 +224,14 @@ async function pollBundleStatus(
224
224
  if (statuses?.value?.length > 0) {
225
225
  consoleLog("Statuses:", statuses);
226
226
  const status = statuses.value[0].confirmation_status;
227
- if (status === "confirmed") {
227
+ if (status === "confirmed" || status === "finalized") {
228
228
  return statuses.value[0].transactions as string[];
229
229
  }
230
230
  const err = statuses.value[0].err;
231
- if (err) {
231
+ // Jito reports a successful bundle as err: { Ok: null }
232
+ if (err && !("Ok" in err && err.Ok === null)) {
232
233
  consoleLog("Jito bundle err:", JSON.stringify(err, null, 2));
233
- throw new Error(err);
234
+ throw new Error(JSON.stringify(err));
234
235
  }
235
236
  }
236
237
  }
@@ -255,10 +256,13 @@ async function sendJitoBundle(
255
256
  }
256
257
  }
257
258
 
258
- if (resp.error?.message === "All providers failed") {
259
- throw new Error(resp.error.responses[0].response.error.message);
259
+ if (resp.error?.responses?.length) {
260
+ const inner = resp.error.responses[0].response?.error;
261
+ throw new Error(
262
+ `${resp.error.message}: ${inner ? (inner.message ?? JSON.stringify(inner)) : "unknown"}`
263
+ );
260
264
  } else if (resp.error) {
261
- throw new Error(resp.error);
265
+ throw new Error(resp.error.message ?? JSON.stringify(resp.error));
262
266
  }
263
267
 
264
268
  const bundleId = resp as string;
@@ -2,6 +2,7 @@ import { PublicKey } from "@solana/web3.js";
2
2
  import { PublicKey as UmiPublicKey } from "@metaplex-foundation/umi";
3
3
  import * as SwbCommon from "@switchboard-xyz/common";
4
4
  import {
5
+ CROSSBAR_URL,
5
6
  PYTH_PRICE_FEED_IDS,
6
7
  PRICES,
7
8
  SWITCHBOARD_PRICE_FEED_IDS,
@@ -160,34 +161,38 @@ export async function getSwitchboardPrices(
160
161
  }
161
162
 
162
163
  const { CrossbarClient } = SwbCommon;
163
- const crossbar = new CrossbarClient("https://crossbar.0.xyz/");
164
+ const crossbar = new CrossbarClient(CROSSBAR_URL);
164
165
 
165
166
  let prices: Record<string, PriceResult> = {};
166
167
  try {
167
168
  prices = await retryWithExponentialBackoff(
168
169
  async () => {
169
- const resp = await crossbar.simulateFeeds(
170
- mints.map((x) => SWITCHBOARD_PRICE_FEED_IDS[x.toString()].feedHash)
170
+ const mintByFeed = new Map(
171
+ mints.map((mint) => [
172
+ SWITCHBOARD_PRICE_FEED_IDS[mint.toString()].feedId,
173
+ mint.toString(),
174
+ ])
175
+ );
176
+ const resp = await crossbar.simulateSolanaFeeds(
177
+ "mainnet",
178
+ Array.from(mintByFeed.keys())
171
179
  );
172
-
173
- const data = resp.flatMap((x) => x.results[0]);
174
- if (
175
- data.filter((x) => !x || isNaN(Number(x)) || Number(x) <= 0).length >
176
- 0
177
- ) {
178
- throw new Error("Unable to fetch Switchboard prices");
179
- }
180
180
 
181
181
  const finalMap: Record<string, PriceResult> = {};
182
182
  for (const item of resp) {
183
- for (const [k, v] of Object.entries(SWITCHBOARD_PRICE_FEED_IDS)) {
184
- if (item.feedHash === v.feedHash) {
185
- const price = Number(item.results[0]);
186
- finalMap[k] = {
187
- realtimePrice: price,
188
- };
189
- }
183
+ const mint = mintByFeed.get(item.feed);
184
+ // Crossbar currently returns the aggregate as `result`; retain `results[0]` for
185
+ // compatibility with the published SDK response type.
186
+ const result = "result" in item ? item.result : item.results[0];
187
+ const price = Number(result);
188
+ if (!mint || !Number.isFinite(price) || price <= 0) {
189
+ throw new Error("Unable to fetch Switchboard prices");
190
190
  }
191
+ finalMap[mint] = { realtimePrice: price };
192
+ }
193
+
194
+ if (Object.keys(finalMap).length !== mintByFeed.size) {
195
+ throw new Error("Unable to fetch all Switchboard prices");
191
196
  }
192
197
  return finalMap;
193
198
  },
@@ -10,6 +10,7 @@ import { AnchorProvider, Idl, Program } from "@coral-xyz/anchor";
10
10
  import * as OnDemand from "@switchboard-xyz/on-demand";
11
11
  import Big from "big.js";
12
12
  import {
13
+ CROSSBAR_URL,
13
14
  PRICES,
14
15
  SWITCHBOARD_PRICE_FEED_IDS,
15
16
  UPDATE_ORACLE_TX_NAME,
@@ -45,17 +46,15 @@ export async function getPullFeed(
45
46
  );
46
47
 
47
48
  consoleLog("Pulling SWB program...");
48
- const { PullFeed, Queue, ON_DEMAND_MAINNET_PID } = OnDemand;
49
+ const { PullFeed, ON_DEMAND_MAINNET_PID } = OnDemand;
49
50
  const sbProgram = await Program.at(ON_DEMAND_MAINNET_PID, provider);
50
51
 
51
- const crossbar = new CrossbarClient("https://integrator-crossbar.mrgn.app/");
52
- const queue = await Queue.loadDefault(sbProgram);
53
- const gateway = await queue.fetchGatewayFromCrossbar(crossbar as any);
52
+ const crossbar = new CrossbarClient(CROSSBAR_URL);
54
53
 
55
54
  consoleLog("Pulled SWB program!");
56
55
  consoleLog("Feed id:", SWITCHBOARD_PRICE_FEED_IDS[mint.toString()].feedId);
57
56
  return {
58
- gateway,
57
+ crossbar,
59
58
  feed: new PullFeed(
60
59
  sbProgram,
61
60
  new PublicKey(SWITCHBOARD_PRICE_FEED_IDS[mint.toString()].feedId)
@@ -68,19 +67,17 @@ export async function buildSwbSubmitResponseTx(
68
67
  signer: Signer,
69
68
  mint: PublicKey
70
69
  ): Promise<TransactionItemInputs | undefined> {
71
- const { feed, gateway } = await getPullFeed(
70
+ const { feed, crossbar } = await getPullFeed(
72
71
  conn,
73
72
  mint,
74
73
  toWeb3JsPublicKey(signer.publicKey)
75
74
  );
76
75
 
77
76
  consoleLog("Fetching crank IX...");
78
- const [pullIxs, responses] = await retryWithExponentialBackoff(
77
+ const [pullIxs, responses, , luts] = await retryWithExponentialBackoff(
79
78
  async () => {
80
79
  const res = await feed.fetchUpdateIx({
81
- gateway: gateway.endpoint(),
82
- chain: "solana",
83
- network: "mainnet-beta",
80
+ crossbarClient: crossbar,
84
81
  });
85
82
  if (!res[1] || !res[1][0].value) {
86
83
  throw new Error("Unable to fetch Switchboard pull IX");
@@ -132,9 +129,14 @@ export async function buildSwbSubmitResponseTx(
132
129
  tx: transactionBuilder(
133
130
  pullIxs.map((x) => getWrappedInstruction(signer, x))
134
131
  ),
135
- lookupTableAddresses: responses
136
- .filter((x) => Boolean(x.oracle.lut?.key))
137
- .map((x) => x.oracle.lut!.key.toString()),
132
+ lookupTableAddresses: Array.from(
133
+ new Set([
134
+ ...luts.map((x) => x.key.toString()),
135
+ ...responses
136
+ .filter((x) => Boolean(x.oracle.lut?.key))
137
+ .map((x) => x.oracle.lut!.key.toString()),
138
+ ])
139
+ ),
138
140
  orderPrio: -2,
139
141
  };
140
142
  }