@haven-fi/solauto-sdk 1.0.302 → 1.0.304

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 (50) 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 +20 -24
  4. package/dist/transactions/transactionUtils.d.ts.map +1 -1
  5. package/dist/transactions/transactionUtils.js +4 -3
  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 -85
  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 -16
  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.map +1 -1
  25. package/dist/utils/solauto/generalUtils.js +2 -1
  26. package/dist/utils/solauto/rebalanceUtils.d.ts.map +1 -1
  27. package/dist/utils/solauto/rebalanceUtils.js +5 -4
  28. package/dist/utils/switchboardUtils.d.ts +7 -0
  29. package/dist/utils/switchboardUtils.d.ts.map +1 -0
  30. package/dist/utils/switchboardUtils.js +41 -0
  31. package/local/createISMAccounts.ts +59 -0
  32. package/local/updateMarginfiLUT.ts +0 -1
  33. package/local/updateSolautoLUT.ts +38 -7
  34. package/package.json +2 -1
  35. package/src/clients/solautoMarginfiClient.ts +18 -27
  36. package/src/constants/README.md +0 -2
  37. package/src/transactions/transactionUtils.ts +8 -3
  38. package/src/transactions/transactionsManager.ts +33 -2
  39. package/src/utils/generalUtils.ts +2 -147
  40. package/src/utils/index.ts +3 -1
  41. package/src/utils/jupiterUtils.ts +13 -3
  42. package/src/utils/marginfiUtils.ts +5 -25
  43. package/src/utils/priceUtils.ts +154 -0
  44. package/src/utils/solanaUtils.ts +1 -2
  45. package/src/utils/solauto/generalUtils.ts +3 -2
  46. package/src/utils/solauto/rebalanceUtils.ts +2 -1
  47. package/src/utils/switchboardUtils.ts +66 -0
  48. package/tests/transactions/solautoMarginfi.ts +29 -24
  49. package/tests/unit/rebalanceCalculations.ts +6 -5
  50. package/local/createSolautoManagerAccount.ts +0 -48
@@ -1,27 +1,5 @@
1
- import {
2
- Connection,
3
- Keypair,
4
- PublicKey,
5
- Transaction,
6
- VersionedTransaction,
7
- } from "@solana/web3.js";
8
- import {
9
- MaybeRpcAccount,
10
- publicKey,
11
- Umi,
12
- PublicKey as UmiPublicKey,
13
- } from "@metaplex-foundation/umi";
14
- import { PYTH_PRICE_FEED_IDS } from "../constants/pythConstants";
15
- import { fromBaseUnit, toBaseUnit } from "./numberUtils";
16
- import { PRICES } from "../constants/solautoConstants";
17
- import {
18
- getProgramId,
19
- PullFeed,
20
- SwitchboardPermission,
21
- } from "@switchboard-xyz/on-demand";
22
- import { AnchorProvider, Idl, Program, Wallet } from "@coral-xyz/anchor";
23
- import switchboardIdl from "../idls/switchboard.json";
24
- import { SWITCHBOARD_PRICE_FEED_IDS } from "../constants/switchboardConstants";
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import { MaybeRpcAccount, publicKey, Umi } from "@metaplex-foundation/umi";
25
3
 
26
4
  export function consoleLog(...args: any[]): void {
27
5
  if ((globalThis as any).LOCAL_TEST) {
@@ -82,129 +60,6 @@ export function zip<T, U>(list1: T[], list2: U[]): [T, U][] {
82
60
  return result;
83
61
  }
84
62
 
85
- export async function fetchTokenPrices(
86
- conn: Connection,
87
- mints: PublicKey[]
88
- ): Promise<number[]> {
89
- const currentTime = currentUnixSeconds();
90
- if (
91
- !mints.some(
92
- (mint) =>
93
- !(mint.toString() in PRICES) ||
94
- currentTime - PRICES[mint.toString()].time > 3
95
- )
96
- ) {
97
- return mints.map((mint) => PRICES[mint.toString()].price);
98
- }
99
-
100
- const pythMints = mints.filter((x) => x.toString() in PYTH_PRICE_FEED_IDS);
101
- const switchboardMints = mints.filter(
102
- (x) => x.toString() in SWITCHBOARD_PRICE_FEED_IDS
103
- );
104
-
105
- const [pythData, switchboardData] = await Promise.all([
106
- zip(pythMints, await getPythPrices(pythMints)),
107
- zip(switchboardMints, await getSwitchboardPrices(conn, switchboardMints)),
108
- ]);
109
-
110
- const prices = mints.map((mint) => {
111
- const item = [...pythData, ...switchboardData].find((data) =>
112
- data[0].equals(mint)
113
- );
114
- return item ? item[1] : 0;
115
- });
116
-
117
- for (var i = 0; i < mints.length; i++) {
118
- PRICES[mints[i].toString()] = {
119
- price: prices[i],
120
- time: currentUnixSeconds(),
121
- };
122
- }
123
-
124
- return prices;
125
- }
126
-
127
- export async function getPythPrices(mints: PublicKey[]) {
128
- const priceFeedIds = mints.map(
129
- (mint) => PYTH_PRICE_FEED_IDS[mint.toString()]
130
- );
131
-
132
- const getReq = async () =>
133
- await fetch(
134
- `https://hermes.pyth.network/v2/updates/price/latest?${priceFeedIds.map((x) => `ids%5B%5D=${x}`).join("&")}`
135
- );
136
-
137
- const prices: number[] = await retryWithExponentialBackoff(
138
- async () => {
139
- let resp = await getReq();
140
- let status = resp.status;
141
- if (status !== 200) {
142
- throw new Error(JSON.stringify(resp));
143
- }
144
-
145
- const json = await resp.json();
146
- const prices = json.parsed.map((x: any) => {
147
- if (x.price.expo > 0) {
148
- return Number(toBaseUnit(Number(x.price.price), x.price.expo));
149
- } else if (x.price.expo < 0) {
150
- return fromBaseUnit(BigInt(x.price.price), Math.abs(x.price.expo));
151
- } else {
152
- return Number(x.price.price);
153
- }
154
- });
155
-
156
- return prices;
157
- },
158
- 5,
159
- 200
160
- );
161
-
162
- return prices;
163
- }
164
-
165
- export async function getSwitchboardPrices(
166
- conn: Connection,
167
- mints: PublicKey[]
168
- ) {
169
- const dummyWallet = {
170
- publicKey: new PublicKey("11111111111111111111111111111111"),
171
- signTransaction: async <T extends Transaction | VersionedTransaction>(
172
- tx: T
173
- ): Promise<T> => tx,
174
- signAllTransactions: async <T extends Transaction | VersionedTransaction>(
175
- txs: T[]
176
- ): Promise<T[]> => txs,
177
- };
178
- const provider = new AnchorProvider(
179
- conn,
180
- dummyWallet,
181
- AnchorProvider.defaultOptions()
182
- );
183
- const program = new Program(switchboardIdl as Idl, provider);
184
-
185
- const results = await Promise.all(
186
- mints.map(async (mint) => {
187
- const feed = new PullFeed(
188
- program,
189
- new PublicKey(SWITCHBOARD_PRICE_FEED_IDS[mint.toString()])
190
- );
191
- const result = await feed.loadData();
192
- return Number(result.result.value) / Math.pow(10, 18);
193
- })
194
- );
195
-
196
- return results;
197
- }
198
-
199
- export function safeGetPrice(
200
- mint: PublicKey | UmiPublicKey | undefined
201
- ): number | undefined {
202
- if (mint && mint?.toString() in PRICES) {
203
- return PRICES[mint!.toString()].price;
204
- }
205
- return undefined;
206
- }
207
-
208
63
  export type ErrorsToThrow = Array<new (...args: any[]) => Error>;
209
64
 
210
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),
@@ -391,18 +383,8 @@ export async function getMarginfiAccountPositionState(
391
383
  return undefined;
392
384
  }
393
385
 
394
- if (
395
- !toWeb3JsPublicKey(supplyBank.group).equals(
396
- new PublicKey(DEFAULT_MARGINFI_GROUP)
397
- )
398
- ) {
399
- // Temporarily disabled for now
400
- return undefined;
401
- }
402
-
403
386
  if (!supplyUsage) {
404
387
  supplyUsage = await getTokenUsage(
405
- conn,
406
388
  supplyBank,
407
389
  true,
408
390
  0,
@@ -419,7 +401,6 @@ export async function getMarginfiAccountPositionState(
419
401
 
420
402
  if (!debtUsage) {
421
403
  debtUsage = await getTokenUsage(
422
- conn,
423
404
  debtBank,
424
405
  false,
425
406
  0,
@@ -429,7 +410,6 @@ export async function getMarginfiAccountPositionState(
429
410
 
430
411
  const supplyPrice = safeGetPrice(supply.mint!)!;
431
412
  let [maxLtv, liqThreshold] = await getMaxLtvAndLiqThreshold(
432
- conn,
433
413
  umi,
434
414
  marginfiGroup ?? new PublicKey(DEFAULT_MARGINFI_GROUP),
435
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 {
@@ -403,7 +404,7 @@ export async function positionStateWithLatestPrices(
403
404
  debtPrice?: number
404
405
  ): Promise<PositionState> {
405
406
  if (!supplyPrice || !debtPrice) {
406
- [supplyPrice, debtPrice] = await fetchTokenPrices(conn, [
407
+ [supplyPrice, debtPrice] = await fetchTokenPrices([
407
408
  toWeb3JsPublicKey(state.supply.mint),
408
409
  toWeb3JsPublicKey(state.debt.mint),
409
410
  ]);
@@ -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
+ }