@haven-fi/solauto-sdk 1.0.667 → 1.0.669

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/marginfi-sdk/errors/marginfi.d.ts +209 -23
  2. package/dist/marginfi-sdk/errors/marginfi.d.ts.map +1 -1
  3. package/dist/marginfi-sdk/errors/marginfi.js +465 -123
  4. package/dist/marginfi-sdk/instructions/lendingAccountDeposit.d.ts +3 -1
  5. package/dist/marginfi-sdk/instructions/lendingAccountDeposit.d.ts.map +1 -1
  6. package/dist/marginfi-sdk/instructions/lendingAccountDeposit.js +1 -0
  7. package/dist/services/rebalance/rebalanceTxBuilder.js +1 -1
  8. package/dist/services/solauto/solautoMarginfiClient.d.ts.map +1 -1
  9. package/dist/services/solauto/solautoMarginfiClient.js +2 -1
  10. package/dist/services/transactions/transactionUtils.d.ts.map +1 -1
  11. package/dist/services/transactions/transactionUtils.js +1 -0
  12. package/dist/solautoPosition/positionUtils.d.ts.map +1 -1
  13. package/dist/solautoPosition/solautoPositionEx.d.ts +3 -3
  14. package/dist/solautoPosition/solautoPositionEx.d.ts.map +1 -1
  15. package/dist/solautoPosition/solautoPositionEx.js +14 -8
  16. package/dist/utils/index.d.ts +1 -1
  17. package/dist/utils/index.d.ts.map +1 -1
  18. package/dist/utils/index.js +1 -1
  19. package/dist/utils/marginfi/data.d.ts +41 -0
  20. package/dist/utils/marginfi/data.d.ts.map +1 -0
  21. package/dist/utils/{marginfiUtils.js → marginfi/data.js} +8 -145
  22. package/dist/utils/marginfi/general.d.ts +27 -0
  23. package/dist/utils/marginfi/general.d.ts.map +1 -0
  24. package/dist/utils/marginfi/general.js +146 -0
  25. package/dist/utils/marginfi/index.d.ts +3 -0
  26. package/dist/utils/marginfi/index.d.ts.map +1 -0
  27. package/dist/utils/marginfi/index.js +18 -0
  28. package/dist/utils/solanaUtils.d.ts.map +1 -1
  29. package/dist/utils/solanaUtils.js +14 -13
  30. package/dist/utils/solautoUtils.d.ts.map +1 -1
  31. package/dist/utils/solautoUtils.js +4 -4
  32. package/local/txSandbox.ts +3 -3
  33. package/package.json +1 -1
  34. package/src/marginfi-sdk/errors/marginfi.ts +583 -122
  35. package/src/marginfi-sdk/instructions/lendingAccountDeposit.ts +7 -0
  36. package/src/services/rebalance/rebalanceTxBuilder.ts +1 -1
  37. package/src/services/solauto/solautoMarginfiClient.ts +2 -1
  38. package/src/services/transactions/transactionUtils.ts +1 -0
  39. package/src/solautoPosition/positionUtils.ts +0 -1
  40. package/src/solautoPosition/solautoPositionEx.ts +24 -9
  41. package/src/utils/index.ts +1 -1
  42. package/src/utils/{marginfiUtils.ts → marginfi/data.ts} +10 -220
  43. package/src/utils/marginfi/general.ts +226 -0
  44. package/src/utils/marginfi/index.ts +2 -0
  45. package/src/utils/solanaUtils.ts +12 -17
  46. package/src/utils/solautoUtils.ts +1 -4
  47. package/tests/transactions/shared.ts +3 -1
  48. package/tests/transactions/solautoMarginfi.ts +4 -2
  49. package/dist/utils/marginfiUtils.d.ts +0 -62
  50. package/dist/utils/marginfiUtils.d.ts.map +0 -1
@@ -8,6 +8,8 @@
8
8
 
9
9
  import {
10
10
  Context,
11
+ Option,
12
+ OptionOrNullable,
11
13
  Pda,
12
14
  PublicKey,
13
15
  Signer,
@@ -17,7 +19,9 @@ import {
17
19
  import {
18
20
  Serializer,
19
21
  array,
22
+ bool,
20
23
  mapSerializer,
24
+ option,
21
25
  struct,
22
26
  u64,
23
27
  u8,
@@ -43,10 +47,12 @@ export type LendingAccountDepositInstructionAccounts = {
43
47
  export type LendingAccountDepositInstructionData = {
44
48
  discriminator: Array<number>;
45
49
  amount: bigint;
50
+ depositUpToLimit: Option<boolean>;
46
51
  };
47
52
 
48
53
  export type LendingAccountDepositInstructionDataArgs = {
49
54
  amount: number | bigint;
55
+ depositUpToLimit: OptionOrNullable<boolean>;
50
56
  };
51
57
 
52
58
  export function getLendingAccountDepositInstructionDataSerializer(): Serializer<
@@ -62,6 +68,7 @@ export function getLendingAccountDepositInstructionDataSerializer(): Serializer<
62
68
  [
63
69
  ['discriminator', array(u8(), { size: 8 })],
64
70
  ['amount', u64()],
71
+ ['depositUpToLimit', option(bool())],
65
72
  ],
66
73
  { description: 'LendingAccountDepositInstructionData' }
67
74
  ),
@@ -210,7 +210,7 @@ export class RebalanceTxBuilder {
210
210
  }
211
211
 
212
212
  if (
213
- !this.client.pos.rebalanceHelper.validRealtimePricesBoost(
213
+ !this.client.pos.rebalance.validRealtimePricesBoost(
214
214
  rebalanceValues.debtAdjustmentUsd
215
215
  )
216
216
  ) {
@@ -259,7 +259,6 @@ export class SolautoMarginfiClient extends SolautoClient {
259
259
  switch (args.__kind) {
260
260
  case "Deposit": {
261
261
  return lendingAccountDeposit(this.umi, {
262
- amount: args.fields[0],
263
262
  signer: this.signer,
264
263
  signerTokenAccount: publicKey(this.signerSupplyTa),
265
264
  marginfiAccount: publicKey(this.marginfiAccountPk),
@@ -268,6 +267,8 @@ export class SolautoMarginfiClient extends SolautoClient {
268
267
  bankLiquidityVault: publicKey(
269
268
  this.marginfiSupplyAccounts.liquidityVault
270
269
  ),
270
+ amount: args.fields[0],
271
+ depositUpToLimit: true,
271
272
  });
272
273
  }
273
274
  case "Borrow": {
@@ -417,6 +417,7 @@ function getSolautoActions(umi: Umi, tx: TransactionBuilder): SolautoAction[] {
417
417
  serializer
418
418
  .serialize({
419
419
  amount: 0,
420
+ depositUpToLimit: true
420
421
  })
421
422
  .slice(0, 8)
422
423
  );
@@ -29,7 +29,6 @@ import {
29
29
  SolautoPositionEx,
30
30
  } from "./solautoPositionEx";
31
31
  import { MarginfiSolautoPositionEx } from "./marginfiSolautoPositionEx";
32
- import { assert } from "console";
33
32
 
34
33
  export function createSolautoSettings(
35
34
  settings: SolautoSettingsParametersInpArgs
@@ -91,7 +91,7 @@ export abstract class SolautoPositionEx {
91
91
  private _supplyPrice?: number;
92
92
  private _debtPrice?: number;
93
93
 
94
- public rebalanceHelper!: PositionRebalanceHelper;
94
+ public rebalance!: PositionRebalanceHelper;
95
95
 
96
96
  constructor(args: PositionExArgs) {
97
97
  this.umi = args.umi;
@@ -120,7 +120,7 @@ export abstract class SolautoPositionEx {
120
120
  this._data = args.data;
121
121
  this.firstState = { ...args.data.state };
122
122
 
123
- this.rebalanceHelper = new PositionRebalanceHelper(this);
123
+ this.rebalance = new PositionRebalanceHelper(this);
124
124
  }
125
125
 
126
126
  abstract lendingPool(): Promise<PublicKey>;
@@ -288,9 +288,13 @@ export abstract class SolautoPositionEx {
288
288
  }
289
289
 
290
290
  eligibleForRebalance(
291
- bpsDistanceThreshold: number = 0
291
+ bpsDistanceThreshold: number = 0,
292
+ skipExtraChecks?: boolean
292
293
  ): RebalanceAction | undefined {
293
- return this.rebalanceHelper.eligibleForRebalance(bpsDistanceThreshold);
294
+ return this.rebalance.eligibleForRebalance(
295
+ bpsDistanceThreshold,
296
+ skipExtraChecks
297
+ );
294
298
  }
295
299
 
296
300
  eligibleForRefresh(): boolean {
@@ -457,11 +461,21 @@ class PositionRebalanceHelper {
457
461
  }
458
462
 
459
463
  private validBoostFromHere() {
464
+ const realtimeSupplyUsd = this.pos.supplyUsd(PriceType.Realtime);
465
+ const realtimeDebtUsd = this.pos.debtUsd(PriceType.Realtime);
466
+
467
+ if (
468
+ realtimeSupplyUsd === this.pos.supplyUsd(PriceType.Ema) &&
469
+ realtimeDebtUsd === this.pos.debtUsd(PriceType.Ema)
470
+ ) {
471
+ return true;
472
+ }
473
+
460
474
  const { debtAdjustmentUsd } = getDebtAdjustment(
461
475
  this.pos.state.liqThresholdBps,
462
476
  {
463
- supplyUsd: this.pos.supplyUsd(PriceType.Realtime),
464
- debtUsd: this.pos.debtUsd(PriceType.Realtime),
477
+ supplyUsd: realtimeSupplyUsd,
478
+ debtUsd: realtimeDebtUsd,
465
479
  },
466
480
  this.pos.boostToBps,
467
481
  { solauto: 25, lpBorrow: 0, flashLoan: 0 } // Undershoot fees
@@ -471,7 +485,8 @@ class PositionRebalanceHelper {
471
485
  }
472
486
 
473
487
  eligibleForRebalance(
474
- bpsDistanceThreshold: number
488
+ bpsDistanceThreshold: number,
489
+ skipExtraChecks?: boolean
475
490
  ): RebalanceAction | undefined {
476
491
  if (!this.pos.settings || !this.pos.supplyUsd()) {
477
492
  return undefined;
@@ -488,8 +503,8 @@ class PositionRebalanceHelper {
488
503
  return "repay";
489
504
  } else if (
490
505
  realtimeLiqUtilRateBps - this.pos.boostFromBps <= bpsDistanceThreshold &&
491
- this.validBoostFromHere() &&
492
- this.sufficientLiquidityToBoost()
506
+ (!skipExtraChecks ||
507
+ (this.validBoostFromHere() && this.sufficientLiquidityToBoost()))
493
508
  ) {
494
509
  return "boost";
495
510
  }
@@ -3,7 +3,7 @@ export * from "./generalUtils";
3
3
  export * from "./instructionUtils";
4
4
  export * from "./jitoUtils";
5
5
  export * from "./jupiterUtils";
6
- export * from "./marginfiUtils";
6
+ export * from "./marginfi";
7
7
  export * from "./numberUtils";
8
8
  export * from "./solautoUtils";
9
9
  export * from "./solanaUtils";
@@ -1,37 +1,28 @@
1
1
  import { PublicKey } from "@solana/web3.js";
2
- import { AccountMeta, Program, publicKey, Umi } from "@metaplex-foundation/umi";
2
+ import { publicKey, Umi } from "@metaplex-foundation/umi";
3
3
  import {
4
- fromWeb3JsPublicKey,
5
4
  toWeb3JsPublicKey,
6
5
  } from "@metaplex-foundation/umi-web3js-adapters";
7
- import { ProgramEnv, MarginfiAssetAccounts } from "../types";
8
- import { PositionState, PositionTokenState, PriceType } from "../generated";
6
+ import { ProgramEnv } from "../../types";
7
+ import { PositionState, PositionTokenState, PriceType } from "../../generated";
9
8
  import {
10
9
  ALL_SUPPORTED_TOKENS,
11
10
  getMarginfiAccounts,
12
- MARGINFI_SPONSORED_SHARD_ID,
13
- MarginfiBankAccountsMap,
14
- PYTH_SPONSORED_SHARD_ID,
15
11
  TOKEN_INFO,
16
12
  USD_DECIMALS,
17
- } from "../constants";
13
+ } from "../../constants";
18
14
  import {
19
- Balance,
20
15
  Bank,
21
16
  deserializeMarginfiAccount,
22
- fetchBank,
23
17
  getMarginfiAccountSize,
24
- getMarginfiErrorFromCode,
25
- getMarginfiErrorFromName,
26
18
  MarginfiAccount,
27
19
  OracleSetup,
28
- safeFetchAllBank,
29
20
  safeFetchBank,
30
21
  safeFetchMarginfiAccount,
31
- } from "../marginfi-sdk";
32
- import { ContextUpdates } from "./solautoUtils";
33
- import { fetchTokenPrices, safeGetPrice } from "./priceUtils";
34
- import { currentUnixSeconds, validPubkey } from "./generalUtils";
22
+ } from "../../marginfi-sdk";
23
+ import { ContextUpdates } from "../solautoUtils";
24
+ import { fetchTokenPrices, safeGetPrice } from "../priceUtils";
25
+ import { currentUnixSeconds, validPubkey } from "../generalUtils";
35
26
  import {
36
27
  bytesToI80F48,
37
28
  calcNetWorthUsd,
@@ -39,198 +30,8 @@ import {
39
30
  getLiqUtilzationRateBps,
40
31
  toBaseUnit,
41
32
  toBps,
42
- } from "./numberUtils";
43
- import { getTokenAccountData } from "./accountUtils";
44
- import {
45
- getMostUpToDatePythOracle,
46
- getPythPushOracleAddress,
47
- } from "./pythUtils";
48
- import { getAccountMeta } from "./solanaUtils";
49
-
50
- export function createDynamicMarginfiProgram(env?: ProgramEnv): Program {
51
- return {
52
- name: "marginfi",
53
- publicKey: publicKey(getMarginfiAccounts(env ?? "Prod").program),
54
- getErrorFromCode(code: number, cause?: Error) {
55
- return getMarginfiErrorFromCode(code, this, cause);
56
- },
57
- getErrorFromName(name: string, cause?: Error) {
58
- return getMarginfiErrorFromName(name, this, cause);
59
- },
60
- isOnCluster() {
61
- return true;
62
- },
63
- };
64
- }
65
-
66
- export function umiWithMarginfiProgram(umi: Umi, marginfiEnv?: ProgramEnv) {
67
- return umi.use({
68
- install(umi) {
69
- umi.programs.add(
70
- createDynamicMarginfiProgram(marginfiEnv ?? "Prod"),
71
- false
72
- );
73
- },
74
- });
75
- }
76
-
77
- export async function getAllBankRelatedAccounts(
78
- umi: Umi,
79
- bankAccountsMap: MarginfiBankAccountsMap
80
- ): Promise<PublicKey[]> {
81
- const banks = Object.values(bankAccountsMap).flatMap((group) =>
82
- Object.values(group).map((accounts) => accounts.bank)
83
- );
84
- const banksData = await safeFetchAllBank(
85
- umi,
86
- banks.map((x) => publicKey(x))
87
- );
88
-
89
- const oracles = banksData
90
- .map((bank) => {
91
- const oracleKey = toWeb3JsPublicKey(bank.config.oracleKeys[0]);
92
- return bank.config.oracleSetup === OracleSetup.PythPushOracle
93
- ? [
94
- getPythPushOracleAddress(oracleKey, PYTH_SPONSORED_SHARD_ID),
95
- getPythPushOracleAddress(oracleKey, MARGINFI_SPONSORED_SHARD_ID),
96
- ]
97
- : [oracleKey];
98
- })
99
- .flat()
100
- .map((x) => x.toString());
101
-
102
- const otherAccounts = Object.entries(bankAccountsMap).flatMap(
103
- ([groupName, tokenMap]) =>
104
- Object.values(tokenMap).flatMap((accounts) => [
105
- groupName,
106
- accounts.liquidityVault,
107
- accounts.vaultAuthority,
108
- ])
109
- );
110
-
111
- return Array.from(new Set([...banks, ...oracles, ...otherAccounts]))
112
- .filter((x) => x !== PublicKey.default.toString())
113
- .map((x) => new PublicKey(x));
114
- }
115
-
116
- export async function fetchBankAddresses(umi: Umi, bankPk: PublicKey) {
117
- const bank = await fetchBank(umi, fromWeb3JsPublicKey(bankPk));
118
- const liquidityVault = toWeb3JsPublicKey(bank!.liquidityVault);
119
- const vaultAuthority = (await getTokenAccountData(umi, liquidityVault))
120
- ?.owner;
121
- const priceOracle = await getMarginfiPriceOracle(umi, { data: bank });
122
-
123
- return {
124
- bank: bankPk,
125
- liquidityVault,
126
- vaultAuthority,
127
- priceOracle,
128
- };
129
- }
130
-
131
- export async function getMarginfiPriceOracle(
132
- umi: Umi,
133
- bank: { pk?: PublicKey; data?: Bank }
134
- ) {
135
- if (!bank.data) {
136
- bank.data = await fetchBank(umi, fromWeb3JsPublicKey(bank.pk!));
137
- }
138
-
139
- const oracleKey = toWeb3JsPublicKey(bank.data.config.oracleKeys[0]);
140
- const priceOracle =
141
- bank.data.config.oracleSetup === OracleSetup.PythPushOracle
142
- ? await getMostUpToDatePythOracle(umi, [
143
- getPythPushOracleAddress(oracleKey, PYTH_SPONSORED_SHARD_ID),
144
- getPythPushOracleAddress(oracleKey, MARGINFI_SPONSORED_SHARD_ID),
145
- ])
146
- : oracleKey;
147
-
148
- return priceOracle;
149
- }
150
-
151
- interface AllMarginfiAssetAccounts extends MarginfiAssetAccounts {
152
- mint: PublicKey;
153
- }
154
-
155
- export function findMarginfiAccounts(
156
- bank: PublicKey
157
- ): AllMarginfiAssetAccounts {
158
- const search = (bankAccounts: MarginfiBankAccountsMap) => {
159
- for (const group in bankAccounts) {
160
- for (const key in bankAccounts[group]) {
161
- const account = bankAccounts[group][key];
162
- if (
163
- account.bank.toString().toLowerCase() ===
164
- bank.toString().toLowerCase()
165
- ) {
166
- return { ...account, mint: new PublicKey(key) };
167
- }
168
- }
169
- }
170
- };
171
-
172
- let res = search(getMarginfiAccounts("Prod").bankAccounts);
173
- if (res) {
174
- return res;
175
- }
176
- res = search(getMarginfiAccounts("Staging").bankAccounts);
177
- if (res) {
178
- return res;
179
- }
180
-
181
- throw new Error(`Marginfi accounts not found by the bank: ${bank}`);
182
- }
183
-
184
- export async function getRemainingAccountsForMarginfiHealthCheck(
185
- umi: Umi,
186
- balance: Balance
187
- ): Promise<AccountMeta[]> {
188
- if (!balance.active) {
189
- return [];
190
- }
191
- const priceOracle = await getMarginfiPriceOracle(umi, {
192
- pk: toWeb3JsPublicKey(balance.bankPk),
193
- });
194
- return [
195
- getAccountMeta(toWeb3JsPublicKey(balance.bankPk)),
196
- getAccountMeta(priceOracle),
197
- ];
198
- }
199
-
200
- export function calcMarginfiMaxLtvAndLiqThresholdBps(
201
- supplyBank: Bank,
202
- debtBank: Bank,
203
- supplyPrice: number
204
- ): [number, number] {
205
- let maxLtv =
206
- bytesToI80F48(supplyBank.config.assetWeightInit.value) /
207
- bytesToI80F48(debtBank.config.liabilityWeightInit.value);
208
- const liqThreshold =
209
- bytesToI80F48(supplyBank.config.assetWeightMaint.value) /
210
- bytesToI80F48(debtBank.config.liabilityWeightMaint.value);
211
-
212
- const totalDepositedUsdValue =
213
- fromBaseUnit(
214
- BigInt(
215
- Math.round(
216
- bytesToI80F48(supplyBank.totalAssetShares.value) *
217
- bytesToI80F48(supplyBank.assetShareValue.value)
218
- )
219
- ),
220
- supplyBank.mintDecimals
221
- ) * supplyPrice!;
222
- if (
223
- supplyBank.config.totalAssetValueInitLimit !== BigInt(0) &&
224
- totalDepositedUsdValue > supplyBank.config.totalAssetValueInitLimit
225
- ) {
226
- const discount =
227
- Number(supplyBank.config.totalAssetValueInitLimit) /
228
- totalDepositedUsdValue;
229
- maxLtv = maxLtv * Number(discount);
230
- }
231
-
232
- return [toBps(maxLtv, "Floor"), toBps(liqThreshold, "Floor")];
233
- }
33
+ } from "../numberUtils";
34
+ import { calcMarginfiMaxLtvAndLiqThresholdBps, marginfiAccountEmpty } from "./general";
234
35
 
235
36
  export async function getMarginfiMaxLtvAndLiqThresholdBps(
236
37
  umi: Umi,
@@ -777,14 +578,3 @@ export function getUpToDateShareValues(bank: Bank): [number, number] {
777
578
  ),
778
579
  ];
779
580
  }
780
-
781
- export function marginfiAccountEmpty(marginfiAccount: MarginfiAccount) {
782
- return (
783
- marginfiAccount.lendingAccount.balances.find(
784
- (x) =>
785
- x.bankPk.toString() !== PublicKey.default.toString() &&
786
- (bytesToI80F48(x.assetShares.value) > 0.000001 ||
787
- bytesToI80F48(x.liabilityShares.value) > 0.000001)
788
- ) === undefined
789
- );
790
- }
@@ -0,0 +1,226 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import { AccountMeta, Program, publicKey, Umi } from "@metaplex-foundation/umi";
3
+ import {
4
+ fromWeb3JsPublicKey,
5
+ toWeb3JsPublicKey,
6
+ } from "@metaplex-foundation/umi-web3js-adapters";
7
+ import { ProgramEnv, MarginfiAssetAccounts } from "../../types";
8
+ import {
9
+ getMarginfiAccounts,
10
+ MARGINFI_SPONSORED_SHARD_ID,
11
+ MarginfiBankAccountsMap,
12
+ PYTH_SPONSORED_SHARD_ID,
13
+ } from "../../constants";
14
+ import {
15
+ Balance,
16
+ Bank,
17
+ fetchBank,
18
+ getMarginfiErrorFromCode,
19
+ getMarginfiErrorFromName,
20
+ MarginfiAccount,
21
+ OracleSetup,
22
+ safeFetchAllBank,
23
+ } from "../../marginfi-sdk";
24
+ import { bytesToI80F48, fromBaseUnit, toBps } from "../numberUtils";
25
+ import { getTokenAccountData } from "../accountUtils";
26
+ import {
27
+ getMostUpToDatePythOracle,
28
+ getPythPushOracleAddress,
29
+ } from "../pythUtils";
30
+ import { getAccountMeta } from "../solanaUtils";
31
+
32
+ export function createDynamicMarginfiProgram(env?: ProgramEnv): Program {
33
+ return {
34
+ name: "marginfi",
35
+ publicKey: publicKey(getMarginfiAccounts(env ?? "Prod").program),
36
+ getErrorFromCode(code: number, cause?: Error) {
37
+ return getMarginfiErrorFromCode(code, this, cause);
38
+ },
39
+ getErrorFromName(name: string, cause?: Error) {
40
+ return getMarginfiErrorFromName(name, this, cause);
41
+ },
42
+ isOnCluster() {
43
+ return true;
44
+ },
45
+ };
46
+ }
47
+
48
+ export function umiWithMarginfiProgram(umi: Umi, marginfiEnv?: ProgramEnv) {
49
+ return umi.use({
50
+ install(umi) {
51
+ umi.programs.add(
52
+ createDynamicMarginfiProgram(marginfiEnv ?? "Prod"),
53
+ false
54
+ );
55
+ },
56
+ });
57
+ }
58
+
59
+ export async function getAllBankRelatedAccounts(
60
+ umi: Umi,
61
+ bankAccountsMap: MarginfiBankAccountsMap
62
+ ): Promise<PublicKey[]> {
63
+ const banks = Object.values(bankAccountsMap).flatMap((group) =>
64
+ Object.values(group).map((accounts) => accounts.bank)
65
+ );
66
+ const banksData = await safeFetchAllBank(
67
+ umi,
68
+ banks.map((x) => publicKey(x))
69
+ );
70
+
71
+ const oracles = banksData
72
+ .map((bank) => {
73
+ const oracleKey = toWeb3JsPublicKey(bank.config.oracleKeys[0]);
74
+ return bank.config.oracleSetup === OracleSetup.PythPushOracle
75
+ ? [
76
+ getPythPushOracleAddress(oracleKey, PYTH_SPONSORED_SHARD_ID),
77
+ getPythPushOracleAddress(oracleKey, MARGINFI_SPONSORED_SHARD_ID),
78
+ ]
79
+ : [oracleKey];
80
+ })
81
+ .flat()
82
+ .map((x) => x.toString());
83
+
84
+ const otherAccounts = Object.entries(bankAccountsMap).flatMap(
85
+ ([groupName, tokenMap]) =>
86
+ Object.values(tokenMap).flatMap((accounts) => [
87
+ groupName,
88
+ accounts.liquidityVault,
89
+ accounts.vaultAuthority,
90
+ ])
91
+ );
92
+
93
+ return Array.from(new Set([...banks, ...oracles, ...otherAccounts]))
94
+ .filter((x) => x !== PublicKey.default.toString())
95
+ .map((x) => new PublicKey(x));
96
+ }
97
+
98
+ export async function fetchBankAddresses(umi: Umi, bankPk: PublicKey) {
99
+ const bank = await fetchBank(umi, fromWeb3JsPublicKey(bankPk));
100
+ const liquidityVault = toWeb3JsPublicKey(bank!.liquidityVault);
101
+ const vaultAuthority = (await getTokenAccountData(umi, liquidityVault))
102
+ ?.owner;
103
+ const priceOracle = await getMarginfiPriceOracle(umi, { data: bank });
104
+
105
+ return {
106
+ bank: bankPk,
107
+ liquidityVault,
108
+ vaultAuthority,
109
+ priceOracle,
110
+ };
111
+ }
112
+
113
+ export async function getMarginfiPriceOracle(
114
+ umi: Umi,
115
+ bank: { pk?: PublicKey; data?: Bank }
116
+ ) {
117
+ if (!bank.data) {
118
+ bank.data = await fetchBank(umi, fromWeb3JsPublicKey(bank.pk!));
119
+ }
120
+
121
+ const oracleKey = toWeb3JsPublicKey(bank.data.config.oracleKeys[0]);
122
+ const priceOracle =
123
+ bank.data.config.oracleSetup === OracleSetup.PythPushOracle
124
+ ? await getMostUpToDatePythOracle(umi, [
125
+ getPythPushOracleAddress(oracleKey, PYTH_SPONSORED_SHARD_ID),
126
+ getPythPushOracleAddress(oracleKey, MARGINFI_SPONSORED_SHARD_ID),
127
+ ])
128
+ : oracleKey;
129
+
130
+ return priceOracle;
131
+ }
132
+
133
+ interface AllMarginfiAssetAccounts extends MarginfiAssetAccounts {
134
+ mint: PublicKey;
135
+ }
136
+
137
+ export function findMarginfiAccounts(
138
+ bank: PublicKey
139
+ ): AllMarginfiAssetAccounts {
140
+ const search = (bankAccounts: MarginfiBankAccountsMap) => {
141
+ for (const group in bankAccounts) {
142
+ for (const key in bankAccounts[group]) {
143
+ const account = bankAccounts[group][key];
144
+ if (
145
+ account.bank.toString().toLowerCase() ===
146
+ bank.toString().toLowerCase()
147
+ ) {
148
+ return { ...account, mint: new PublicKey(key) };
149
+ }
150
+ }
151
+ }
152
+ };
153
+
154
+ let res = search(getMarginfiAccounts("Prod").bankAccounts);
155
+ if (res) {
156
+ return res;
157
+ }
158
+ res = search(getMarginfiAccounts("Staging").bankAccounts);
159
+ if (res) {
160
+ return res;
161
+ }
162
+
163
+ throw new Error(`Marginfi accounts not found by the bank: ${bank}`);
164
+ }
165
+
166
+ export async function getRemainingAccountsForMarginfiHealthCheck(
167
+ umi: Umi,
168
+ balance: Balance
169
+ ): Promise<AccountMeta[]> {
170
+ if (!balance.active) {
171
+ return [];
172
+ }
173
+ const priceOracle = await getMarginfiPriceOracle(umi, {
174
+ pk: toWeb3JsPublicKey(balance.bankPk),
175
+ });
176
+ return [
177
+ getAccountMeta(toWeb3JsPublicKey(balance.bankPk)),
178
+ getAccountMeta(priceOracle),
179
+ ];
180
+ }
181
+
182
+ export function calcMarginfiMaxLtvAndLiqThresholdBps(
183
+ supplyBank: Bank,
184
+ debtBank: Bank,
185
+ supplyPrice: number
186
+ ): [number, number] {
187
+ let maxLtv =
188
+ bytesToI80F48(supplyBank.config.assetWeightInit.value) /
189
+ bytesToI80F48(debtBank.config.liabilityWeightInit.value);
190
+ const liqThreshold =
191
+ bytesToI80F48(supplyBank.config.assetWeightMaint.value) /
192
+ bytesToI80F48(debtBank.config.liabilityWeightMaint.value);
193
+
194
+ const totalDepositedUsdValue =
195
+ fromBaseUnit(
196
+ BigInt(
197
+ Math.round(
198
+ bytesToI80F48(supplyBank.totalAssetShares.value) *
199
+ bytesToI80F48(supplyBank.assetShareValue.value)
200
+ )
201
+ ),
202
+ supplyBank.mintDecimals
203
+ ) * supplyPrice!;
204
+ if (
205
+ supplyBank.config.totalAssetValueInitLimit !== BigInt(0) &&
206
+ totalDepositedUsdValue > supplyBank.config.totalAssetValueInitLimit
207
+ ) {
208
+ const discount =
209
+ Number(supplyBank.config.totalAssetValueInitLimit) /
210
+ totalDepositedUsdValue;
211
+ maxLtv = maxLtv * Number(discount);
212
+ }
213
+
214
+ return [toBps(maxLtv, "Floor"), toBps(liqThreshold, "Floor")];
215
+ }
216
+
217
+ export function marginfiAccountEmpty(marginfiAccount: MarginfiAccount) {
218
+ return (
219
+ marginfiAccount.lendingAccount.balances.find(
220
+ (x) =>
221
+ x.bankPk.toString() !== PublicKey.default.toString() &&
222
+ (bytesToI80F48(x.assetShares.value) > 0.000001 ||
223
+ bytesToI80F48(x.liabilityShares.value) > 0.000001)
224
+ ) === undefined
225
+ );
226
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./data";
2
+ export * from "./general";