@haven-fi/solauto-sdk 1.0.303 → 1.0.305

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 (51) hide show
  1. package/dist/clients/solautoMarginfiClient.d.ts +1 -2
  2. package/dist/clients/solautoMarginfiClient.d.ts.map +1 -1
  3. package/dist/clients/solautoMarginfiClient.js +22 -26
  4. package/dist/transactions/transactionUtils.d.ts.map +1 -1
  5. package/dist/transactions/transactionUtils.js +5 -4
  6. package/dist/transactions/transactionsManager.d.ts.map +1 -1
  7. package/dist/transactions/transactionsManager.js +15 -0
  8. package/dist/utils/generalUtils.d.ts +2 -6
  9. package/dist/utils/generalUtils.d.ts.map +1 -1
  10. package/dist/utils/generalUtils.js +0 -91
  11. package/dist/utils/index.d.ts +2 -0
  12. package/dist/utils/index.d.ts.map +1 -1
  13. package/dist/utils/index.js +2 -0
  14. package/dist/utils/jupiterUtils.d.ts.map +1 -1
  15. package/dist/utils/jupiterUtils.js +10 -2
  16. package/dist/utils/marginfiUtils.d.ts +2 -2
  17. package/dist/utils/marginfiUtils.d.ts.map +1 -1
  18. package/dist/utils/marginfiUtils.js +13 -12
  19. package/dist/utils/priceUtils.d.ts +12 -0
  20. package/dist/utils/priceUtils.d.ts.map +1 -0
  21. package/dist/utils/priceUtils.js +97 -0
  22. package/dist/utils/solanaUtils.d.ts.map +1 -1
  23. package/dist/utils/solanaUtils.js +1 -1
  24. package/dist/utils/solauto/generalUtils.d.ts +1 -1
  25. package/dist/utils/solauto/generalUtils.d.ts.map +1 -1
  26. package/dist/utils/solauto/generalUtils.js +3 -2
  27. package/dist/utils/solauto/rebalanceUtils.d.ts.map +1 -1
  28. package/dist/utils/solauto/rebalanceUtils.js +5 -4
  29. package/dist/utils/switchboardUtils.d.ts +7 -0
  30. package/dist/utils/switchboardUtils.d.ts.map +1 -0
  31. package/dist/utils/switchboardUtils.js +41 -0
  32. package/local/createISMAccounts.ts +59 -0
  33. package/local/updateMarginfiLUT.ts +0 -1
  34. package/local/updateSolautoLUT.ts +38 -7
  35. package/package.json +2 -1
  36. package/src/clients/solautoMarginfiClient.ts +17 -28
  37. package/src/constants/README.md +0 -2
  38. package/src/transactions/transactionUtils.ts +8 -4
  39. package/src/transactions/transactionsManager.ts +33 -2
  40. package/src/utils/generalUtils.ts +2 -152
  41. package/src/utils/index.ts +3 -1
  42. package/src/utils/jupiterUtils.ts +13 -3
  43. package/src/utils/marginfiUtils.ts +5 -16
  44. package/src/utils/priceUtils.ts +154 -0
  45. package/src/utils/solanaUtils.ts +1 -2
  46. package/src/utils/solauto/generalUtils.ts +3 -3
  47. package/src/utils/solauto/rebalanceUtils.ts +2 -1
  48. package/src/utils/switchboardUtils.ts +66 -0
  49. package/tests/transactions/solautoMarginfi.ts +35 -33
  50. package/tests/unit/rebalanceCalculations.ts +6 -6
  51. package/local/createSolautoManagerAccount.ts +0 -48
@@ -1,24 +1,5 @@
1
- import {
2
- Connection,
3
- PublicKey,
4
- Transaction,
5
- VersionedTransaction,
6
- } from "@solana/web3.js";
7
- import {
8
- MaybeRpcAccount,
9
- publicKey,
10
- Umi,
11
- PublicKey as UmiPublicKey,
12
- } from "@metaplex-foundation/umi";
13
- import { PYTH_PRICE_FEED_IDS } from "../constants/pythConstants";
14
- import { fromBaseUnit, toBaseUnit } from "./numberUtils";
15
- import { PRICES } from "../constants/solautoConstants";
16
- import {
17
- PullFeed,
18
- } from "@switchboard-xyz/on-demand";
19
- import { AnchorProvider, Idl, Program } from "@coral-xyz/anchor";
20
- import switchboardIdl from "../idls/switchboard.json";
21
- import { SWITCHBOARD_PRICE_FEED_IDS } from "../constants/switchboardConstants";
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import { MaybeRpcAccount, publicKey, Umi } from "@metaplex-foundation/umi";
22
3
 
23
4
  export function consoleLog(...args: any[]): void {
24
5
  if ((globalThis as any).LOCAL_TEST) {
@@ -79,137 +60,6 @@ export function zip<T, U>(list1: T[], list2: U[]): [T, U][] {
79
60
  return result;
80
61
  }
81
62
 
82
- export async function fetchTokenPrices(
83
- conn: Connection,
84
- mints: PublicKey[]
85
- ): Promise<number[]> {
86
- const currentTime = currentUnixSeconds();
87
- if (
88
- !mints.some(
89
- (mint) =>
90
- !(mint.toString() in PRICES) ||
91
- currentTime - PRICES[mint.toString()].time > 3
92
- )
93
- ) {
94
- return mints.map((mint) => PRICES[mint.toString()].price);
95
- }
96
-
97
- const pythMints = mints.filter((x) => x.toString() in PYTH_PRICE_FEED_IDS);
98
- const switchboardMints = mints.filter(
99
- (x) => x.toString() in SWITCHBOARD_PRICE_FEED_IDS
100
- );
101
-
102
- const [pythData, switchboardData] = await Promise.all([
103
- zip(pythMints, await getPythPrices(pythMints)),
104
- zip(switchboardMints, await getSwitchboardPrices(conn, switchboardMints)),
105
- ]);
106
-
107
- const prices = mints.map((mint) => {
108
- const item = [...pythData, ...switchboardData].find((data) =>
109
- data[0].equals(mint)
110
- );
111
- return item ? item[1] : 0;
112
- });
113
-
114
- for (var i = 0; i < mints.length; i++) {
115
- PRICES[mints[i].toString()] = {
116
- price: prices[i],
117
- time: currentUnixSeconds(),
118
- };
119
- }
120
-
121
- return prices;
122
- }
123
-
124
- export async function getPythPrices(mints: PublicKey[]) {
125
- if (mints.length === 0) {
126
- return [];
127
- }
128
-
129
- const priceFeedIds = mints.map(
130
- (mint) => PYTH_PRICE_FEED_IDS[mint.toString()]
131
- );
132
-
133
- const getReq = async () =>
134
- await fetch(
135
- `https://hermes.pyth.network/v2/updates/price/latest?${priceFeedIds.map((x) => `ids%5B%5D=${x}`).join("&")}`
136
- );
137
-
138
- const prices: number[] = await retryWithExponentialBackoff(
139
- async () => {
140
- let resp = await getReq();
141
- let status = resp.status;
142
- if (status !== 200) {
143
- throw new Error(JSON.stringify(resp));
144
- }
145
-
146
- const json = await resp.json();
147
- const prices = json.parsed.map((x: any) => {
148
- if (x.price.expo > 0) {
149
- return Number(toBaseUnit(Number(x.price.price), x.price.expo));
150
- } else if (x.price.expo < 0) {
151
- return fromBaseUnit(BigInt(x.price.price), Math.abs(x.price.expo));
152
- } else {
153
- return Number(x.price.price);
154
- }
155
- });
156
-
157
- return prices;
158
- },
159
- 5,
160
- 200
161
- );
162
-
163
- return prices;
164
- }
165
-
166
- export async function getSwitchboardPrices(
167
- conn: Connection,
168
- mints: PublicKey[]
169
- ) {
170
- if (mints.length === 0) {
171
- return [];
172
- }
173
-
174
- const dummyWallet = {
175
- publicKey: new PublicKey("11111111111111111111111111111111"),
176
- signTransaction: async <T extends Transaction | VersionedTransaction>(
177
- tx: T
178
- ): Promise<T> => tx,
179
- signAllTransactions: async <T extends Transaction | VersionedTransaction>(
180
- txs: T[]
181
- ): Promise<T[]> => txs,
182
- };
183
- const provider = new AnchorProvider(
184
- conn,
185
- dummyWallet,
186
- AnchorProvider.defaultOptions()
187
- );
188
- const program = new Program(switchboardIdl as Idl, provider);
189
-
190
- const results = await Promise.all(
191
- mints.map(async (mint) => {
192
- const feed = new PullFeed(
193
- program,
194
- new PublicKey(SWITCHBOARD_PRICE_FEED_IDS[mint.toString()])
195
- );
196
- const result = await feed.loadData();
197
- return Number(result.result.value) / Math.pow(10, 18);
198
- })
199
- );
200
-
201
- return results;
202
- }
203
-
204
- export function safeGetPrice(
205
- mint: PublicKey | UmiPublicKey | undefined
206
- ): number | undefined {
207
- if (mint && mint?.toString() in PRICES) {
208
- return PRICES[mint!.toString()].price;
209
- }
210
- return undefined;
211
- }
212
-
213
63
  export type ErrorsToThrow = Array<new (...args: any[]) => Error>;
214
64
 
215
65
  export function retryWithExponentialBackoff<T>(
@@ -4,4 +4,6 @@ export * from './generalUtils';
4
4
  export * from './jupiterUtils';
5
5
  export * from './marginfiUtils';
6
6
  export * from './numberUtils';
7
- export * from './solanaUtils';
7
+ export * from './solanaUtils';
8
+ export * from './priceUtils';
9
+ export * from './switchboardUtils';
@@ -13,6 +13,7 @@ import {
13
13
  } from "@jup-ag/api";
14
14
  import { getTokenAccount } from "./accountUtils";
15
15
  import { consoleLog, retryWithExponentialBackoff } from "./generalUtils";
16
+ import { TOKEN_INFO } from "../constants";
16
17
 
17
18
  const jupApi = createJupiterApiClient();
18
19
 
@@ -54,7 +55,10 @@ export async function getJupSwapTransaction(
54
55
  swapDetails: JupSwapDetails,
55
56
  attemptNum?: number
56
57
  ): Promise<JupSwapTransaction> {
57
- consoleLog("Getting jup quote...");
58
+ const memecoinSwap =
59
+ TOKEN_INFO[swapDetails.inputMint.toString()].isMeme ||
60
+ TOKEN_INFO[swapDetails.outputMint.toString()].isMeme;
61
+
58
62
  const quoteResponse = await retryWithExponentialBackoff(
59
63
  async () =>
60
64
  await jupApi.quoteGet({
@@ -66,7 +70,7 @@ export async function getJupSwapTransaction(
66
70
  : swapDetails.exactIn
67
71
  ? "ExactIn"
68
72
  : undefined,
69
- slippageBps: 50,
73
+ slippageBps: memecoinSwap ? 150 : 50,
70
74
  maxAccounts: !swapDetails.exactOut ? 60 : undefined,
71
75
  }),
72
76
  4,
@@ -90,6 +94,12 @@ export async function getJupSwapTransaction(
90
94
  )
91
95
  ).toString();
92
96
  }
97
+ // else {
98
+ // quoteResponse.inAmount = (
99
+ // parseInt(quoteResponse.inAmount) +
100
+ // Math.ceil(parseInt(quoteResponse.inAmount) * fromBps(priceImpactBps))
101
+ // ).toString();
102
+ // }
93
103
 
94
104
  consoleLog("Getting jup instructions...");
95
105
  const instructions = await retryWithExponentialBackoff(
@@ -143,4 +153,4 @@ export async function getJupSwapTransaction(
143
153
  )
144
154
  ),
145
155
  };
146
- }
156
+ }
@@ -9,11 +9,7 @@ import {
9
9
  safeFetchBank,
10
10
  safeFetchMarginfiAccount,
11
11
  } from "../marginfi-sdk";
12
- import {
13
- currentUnixSeconds,
14
- fetchTokenPrices,
15
- safeGetPrice,
16
- } from "./generalUtils";
12
+ import { currentUnixSeconds } from "./generalUtils";
17
13
  import {
18
14
  bytesToI80F48,
19
15
  fromBaseUnit,
@@ -30,6 +26,7 @@ import { PositionState, PositionTokenUsage } from "../generated";
30
26
  import { USD_DECIMALS } from "../constants/generalAccounts";
31
27
  import { LivePositionUpdates } from "./solauto/generalUtils";
32
28
  import { TOKEN_INFO } from "../constants";
29
+ import { fetchTokenPrices, safeGetPrice } from "./priceUtils";
33
30
 
34
31
  interface AllMarginfiAssetAccounts extends MarginfiAssetAccounts {
35
32
  mint: PublicKey;
@@ -87,7 +84,6 @@ export function calcMaxLtvAndLiqThreshold(
87
84
  }
88
85
 
89
86
  export async function getMaxLtvAndLiqThreshold(
90
- conn: Connection,
91
87
  umi: Umi,
92
88
  marginfiGroup: PublicKey,
93
89
  supply: {
@@ -128,7 +124,7 @@ export async function getMaxLtvAndLiqThreshold(
128
124
  }
129
125
 
130
126
  if (!supplyPrice) {
131
- const [price] = await fetchTokenPrices(conn, [
127
+ const [price] = await fetchTokenPrices([
132
128
  toWeb3JsPublicKey(supply.bank!.mint),
133
129
  ]);
134
130
  supplyPrice = price;
@@ -175,7 +171,7 @@ export async function getAllMarginfiAccountsByAuthority(
175
171
  const positionStates = await Promise.all(
176
172
  marginfiAccounts.map(async (x) => ({
177
173
  publicKey: x.publicKey,
178
- state: await getMarginfiAccountPositionState(conn, umi, {
174
+ state: await getMarginfiAccountPositionState(umi, {
179
175
  pk: toWeb3JsPublicKey(x.publicKey),
180
176
  }),
181
177
  }))
@@ -206,7 +202,6 @@ export async function getAllMarginfiAccountsByAuthority(
206
202
  }
207
203
 
208
204
  async function getTokenUsage(
209
- conn: Connection,
210
205
  bank: Bank | null,
211
206
  isAsset: boolean,
212
207
  shares: number,
@@ -217,7 +212,7 @@ async function getTokenUsage(
217
212
  let marketPrice = 0;
218
213
 
219
214
  if (bank !== null) {
220
- [marketPrice] = await fetchTokenPrices(conn, [
215
+ [marketPrice] = await fetchTokenPrices([
221
216
  toWeb3JsPublicKey(bank.mint),
222
217
  ]);
223
218
  const [assetShareValue, liabilityShareValue] =
@@ -275,7 +270,6 @@ interface BankSelection {
275
270
  type BanksCache = { [group: string]: { [mint: string]: Bank } };
276
271
 
277
272
  export async function getMarginfiAccountPositionState(
278
- conn: Connection,
279
273
  umi: Umi,
280
274
  protocolAccount: { pk: PublicKey; data?: MarginfiAccount },
281
275
  marginfiGroup?: PublicKey,
@@ -360,7 +354,6 @@ export async function getMarginfiAccountPositionState(
360
354
  supply.mint = toWeb3JsPublicKey(supplyBank!.mint);
361
355
  }
362
356
  supplyUsage = await getTokenUsage(
363
- conn,
364
357
  supplyBank!,
365
358
  true,
366
359
  bytesToI80F48(supplyBalances[0].assetShares.value),
@@ -378,7 +371,6 @@ export async function getMarginfiAccountPositionState(
378
371
  debt.mint = toWeb3JsPublicKey(debtBank!.mint);
379
372
  }
380
373
  debtUsage = await getTokenUsage(
381
- conn,
382
374
  debtBank!,
383
375
  false,
384
376
  bytesToI80F48(debtBalances[0].liabilityShares.value),
@@ -393,7 +385,6 @@ export async function getMarginfiAccountPositionState(
393
385
 
394
386
  if (!supplyUsage) {
395
387
  supplyUsage = await getTokenUsage(
396
- conn,
397
388
  supplyBank,
398
389
  true,
399
390
  0,
@@ -410,7 +401,6 @@ export async function getMarginfiAccountPositionState(
410
401
 
411
402
  if (!debtUsage) {
412
403
  debtUsage = await getTokenUsage(
413
- conn,
414
404
  debtBank,
415
405
  false,
416
406
  0,
@@ -420,7 +410,6 @@ export async function getMarginfiAccountPositionState(
420
410
 
421
411
  const supplyPrice = safeGetPrice(supply.mint!)!;
422
412
  let [maxLtv, liqThreshold] = await getMaxLtvAndLiqThreshold(
423
- conn,
424
413
  umi,
425
414
  marginfiGroup ?? new PublicKey(DEFAULT_MARGINFI_GROUP),
426
415
  {
@@ -0,0 +1,154 @@
1
+ import { Connection, PublicKey } from "@solana/web3.js";
2
+ import { PublicKey as UmiPublicKey } from "@metaplex-foundation/umi";
3
+ import { PYTH_PRICE_FEED_IDS } from "../constants/pythConstants";
4
+ import { fromBaseUnit, toBaseUnit } from "./numberUtils";
5
+ import { PRICES } from "../constants/solautoConstants";
6
+ import { SWITCHBOARD_PRICE_FEED_IDS } from "../constants/switchboardConstants";
7
+ import {
8
+ currentUnixSeconds,
9
+ retryWithExponentialBackoff,
10
+ zip,
11
+ } from "./generalUtils";
12
+ import { getPullFeed } from "./switchboardUtils";
13
+
14
+ export async function fetchTokenPrices(
15
+ mints: PublicKey[]
16
+ ): Promise<number[]> {
17
+ const currentTime = currentUnixSeconds();
18
+ if (
19
+ !mints.some(
20
+ (mint) =>
21
+ !(mint.toString() in PRICES) ||
22
+ currentTime - PRICES[mint.toString()].time > 3
23
+ )
24
+ ) {
25
+ return mints.map((mint) => PRICES[mint.toString()].price);
26
+ }
27
+
28
+ const pythMints = mints.filter((x) => x.toString() in PYTH_PRICE_FEED_IDS);
29
+ const switchboardMints = mints.filter(
30
+ (x) => x.toString() in SWITCHBOARD_PRICE_FEED_IDS
31
+ );
32
+
33
+ const [pythData, switchboardData] = await Promise.all([
34
+ zip(pythMints, await getPythPrices(pythMints)),
35
+ zip(switchboardMints, await getJupTokenPrices(switchboardMints)),
36
+ ]);
37
+
38
+ const prices = mints.map((mint) => {
39
+ const item = [...pythData, ...switchboardData].find((data) =>
40
+ data[0].equals(mint)
41
+ );
42
+ return item ? item[1] : 0;
43
+ });
44
+
45
+ for (var i = 0; i < mints.length; i++) {
46
+ PRICES[mints[i].toString()] = {
47
+ price: prices[i],
48
+ time: currentUnixSeconds(),
49
+ };
50
+ }
51
+
52
+ return prices;
53
+ }
54
+
55
+ export async function getPythPrices(mints: PublicKey[]) {
56
+ if (mints.length === 0) {
57
+ return [];
58
+ }
59
+
60
+ const priceFeedIds = mints.map(
61
+ (mint) => PYTH_PRICE_FEED_IDS[mint.toString()]
62
+ );
63
+
64
+ const getReq = async () =>
65
+ await fetch(
66
+ `https://hermes.pyth.network/v2/updates/price/latest?${priceFeedIds.map((x) => `ids%5B%5D=${x}`).join("&")}`
67
+ );
68
+
69
+ const prices: number[] = await retryWithExponentialBackoff(
70
+ async () => {
71
+ let resp = await getReq();
72
+ let status = resp.status;
73
+ if (status !== 200) {
74
+ throw new Error(JSON.stringify(resp));
75
+ }
76
+
77
+ const json = await resp.json();
78
+ const prices = json.parsed.map((x: any) => {
79
+ if (x.price.expo > 0) {
80
+ return Number(toBaseUnit(Number(x.price.price), x.price.expo));
81
+ } else if (x.price.expo < 0) {
82
+ return fromBaseUnit(BigInt(x.price.price), Math.abs(x.price.expo));
83
+ } else {
84
+ return Number(x.price.price);
85
+ }
86
+ });
87
+
88
+ return prices;
89
+ },
90
+ 5,
91
+ 200
92
+ );
93
+
94
+ return prices;
95
+ }
96
+
97
+ export async function getSwitchboardPrices(
98
+ conn: Connection,
99
+ mints: PublicKey[]
100
+ ): Promise<{ mint: PublicKey; price: number; stale: boolean }[]> {
101
+ if (mints.length === 0) {
102
+ return [];
103
+ }
104
+
105
+ const currSlot = await retryWithExponentialBackoff(
106
+ async () => await conn.getSlot("confirmed"),
107
+ 5
108
+ );
109
+
110
+ const results = await Promise.all(
111
+ mints.map(async (mint) => {
112
+ const feed = getPullFeed(conn, mint);
113
+ const result = await feed.loadData();
114
+ const price = Number(result.result.value) / Math.pow(10, 18);
115
+ const stale =
116
+ currSlot > result.result.slot.toNumber() + result.maxStaleness;
117
+
118
+ return { mint, price, stale };
119
+ })
120
+ );
121
+
122
+ return results;
123
+ }
124
+
125
+ export function safeGetPrice(
126
+ mint: PublicKey | UmiPublicKey | undefined
127
+ ): number | undefined {
128
+ if (mint && mint?.toString() in PRICES) {
129
+ return PRICES[mint!.toString()].price;
130
+ }
131
+ return undefined;
132
+ }
133
+
134
+ export async function getJupTokenPrices(mints: PublicKey[]) {
135
+ if (mints.length == 0) {
136
+ return [];
137
+ }
138
+
139
+ const data = await retryWithExponentialBackoff(async () => {
140
+ const res = (
141
+ await fetch(
142
+ "https://api.jup.ag/price/v2?ids=" +
143
+ mints.map((x) => x.toString()).join(",")
144
+ )
145
+ ).json();
146
+ return res;
147
+ }, 6);
148
+
149
+ const prices = Object.values(data.data as { [key: string]: any }).map(
150
+ (x) => parseFloat(x.price as string) as number
151
+ );
152
+
153
+ return prices;
154
+ }
@@ -16,7 +16,6 @@ import {
16
16
  import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
17
17
  import {
18
18
  AddressLookupTableAccount,
19
- Blockhash,
20
19
  BlockhashWithExpiryBlockHeight,
21
20
  ComputeBudgetProgram,
22
21
  Connection,
@@ -318,7 +317,7 @@ async function spamSendTransactionUntilConfirmed(
318
317
  connection: Connection,
319
318
  transaction: Transaction | VersionedTransaction,
320
319
  blockhash: BlockhashWithExpiryBlockHeight,
321
- spamInterval: number = 1000
320
+ spamInterval: number = 3000
322
321
  ): Promise<string> {
323
322
  let transactionSignature: string | null = null;
324
323
 
@@ -22,7 +22,7 @@ import {
22
22
  getSolautoPositionAccountDataSerializer,
23
23
  getSolautoPositionSize,
24
24
  } from "../../generated";
25
- import { currentUnixSeconds, fetchTokenPrices } from "../generalUtils";
25
+ import { currentUnixSeconds } from "../generalUtils";
26
26
  import {
27
27
  fromBaseUnit,
28
28
  getLiqUtilzationRateBps,
@@ -40,6 +40,7 @@ import {
40
40
  getAllMarginfiAccountsByAuthority,
41
41
  } from "../marginfiUtils";
42
42
  import { RebalanceAction, SolautoPositionDetails } from "../../types/solauto";
43
+ import { fetchTokenPrices } from "../priceUtils";
43
44
 
44
45
  export function createDynamicSolautoProgram(programId: PublicKey): Program {
45
46
  return {
@@ -397,13 +398,12 @@ export async function getAllPositionsByAuthority(
397
398
  }
398
399
 
399
400
  export async function positionStateWithLatestPrices(
400
- conn: Connection,
401
401
  state: PositionState,
402
402
  supplyPrice?: number,
403
403
  debtPrice?: number
404
404
  ): Promise<PositionState> {
405
405
  if (!supplyPrice || !debtPrice) {
406
- [supplyPrice, debtPrice] = await fetchTokenPrices(conn, [
406
+ [supplyPrice, debtPrice] = await fetchTokenPrices([
407
407
  toWeb3JsPublicKey(state.supply.mint),
408
408
  toWeb3JsPublicKey(state.debt.mint),
409
409
  ]);
@@ -16,7 +16,7 @@ import {
16
16
  import { toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
17
17
  import { QuoteResponse } from "@jup-ag/api";
18
18
  import { JupSwapDetails } from "../jupiterUtils";
19
- import { currentUnixSeconds, safeGetPrice } from "../generalUtils";
19
+ import { currentUnixSeconds } from "../generalUtils";
20
20
  import {
21
21
  fromBaseUnit,
22
22
  fromBps,
@@ -29,6 +29,7 @@ import {
29
29
  } from "../numberUtils";
30
30
  import { USD_DECIMALS } from "../../constants/generalAccounts";
31
31
  import { RebalanceAction } from "../../types";
32
+ import { safeGetPrice } from "../priceUtils";
32
33
 
33
34
  function getAdditionalAmountToDcaIn(dca: DCASettings): number {
34
35
  if (dca.dcaInBaseUnit === BigInt(0)) {
@@ -0,0 +1,66 @@
1
+ import { AnchorProvider, Idl, Program } from "@coral-xyz/anchor";
2
+ import switchboardIdl from "../idls/switchboard.json";
3
+ import {
4
+ Connection,
5
+ PublicKey,
6
+ Transaction,
7
+ VersionedTransaction,
8
+ } from "@solana/web3.js";
9
+ import { CrossbarClient, PullFeed } from "@switchboard-xyz/on-demand";
10
+ import { SWITCHBOARD_PRICE_FEED_IDS } from "../constants/switchboardConstants";
11
+ import { TransactionItemInputs } from "../types";
12
+ import { Signer, transactionBuilder } from "@metaplex-foundation/umi";
13
+ import {
14
+ fromWeb3JsInstruction,
15
+ toWeb3JsPublicKey,
16
+ } from "@metaplex-foundation/umi-web3js-adapters";
17
+
18
+ export function getPullFeed(
19
+ conn: Connection,
20
+ mint: PublicKey,
21
+ wallet?: PublicKey
22
+ ) {
23
+ const dummyWallet = {
24
+ publicKey: wallet ?? new PublicKey("11111111111111111111111111111111"),
25
+ signTransaction: async <T extends Transaction | VersionedTransaction>(
26
+ tx: T
27
+ ): Promise<T> => tx,
28
+ signAllTransactions: async <T extends Transaction | VersionedTransaction>(
29
+ txs: T[]
30
+ ): Promise<T[]> => txs,
31
+ };
32
+ const provider = new AnchorProvider(
33
+ conn,
34
+ dummyWallet,
35
+ AnchorProvider.defaultOptions()
36
+ );
37
+ const program = new Program(switchboardIdl as Idl, provider);
38
+
39
+ return new PullFeed(
40
+ program,
41
+ new PublicKey(SWITCHBOARD_PRICE_FEED_IDS[mint.toString()])
42
+ );
43
+ }
44
+
45
+ export async function buildSwbSubmitResponseTx(
46
+ conn: Connection,
47
+ signer: Signer,
48
+ mint: PublicKey
49
+ ): Promise<TransactionItemInputs | undefined> {
50
+ const crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");
51
+ const feed = getPullFeed(conn, mint, toWeb3JsPublicKey(signer.publicKey));
52
+ const [pullIx, responses] = await feed.fetchUpdateIx({
53
+ crossbarClient: crossbar,
54
+ });
55
+
56
+ return {
57
+ tx: transactionBuilder().add({
58
+ bytesCreatedOnChain: 0,
59
+ instruction: fromWeb3JsInstruction(pullIx!),
60
+ signers: [signer],
61
+ }),
62
+ lookupTableAddresses: responses
63
+ .filter((x) => Boolean(x.oracle.lut?.key))
64
+ .map((x) => x.oracle.lut!.key.toString()),
65
+ };
66
+ }