@haven-fi/solauto-sdk 1.0.626 → 1.0.627

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 (56) hide show
  1. package/README.md +115 -0
  2. package/dist/constants/marginfiAccounts.d.ts +3 -4
  3. package/dist/constants/marginfiAccounts.d.ts.map +1 -1
  4. package/dist/constants/marginfiAccounts.js +9 -37
  5. package/dist/constants/pythConstants.d.ts +4 -0
  6. package/dist/constants/pythConstants.d.ts.map +1 -1
  7. package/dist/constants/pythConstants.js +5 -1
  8. package/dist/services/flashLoans/marginfiFlProvider.d.ts.map +1 -1
  9. package/dist/services/flashLoans/marginfiFlProvider.js +7 -8
  10. package/dist/services/solauto/solautoClient.d.ts.map +1 -1
  11. package/dist/services/solauto/solautoClient.js +5 -6
  12. package/dist/services/solauto/solautoMarginfiClient.d.ts.map +1 -1
  13. package/dist/services/solauto/solautoMarginfiClient.js +4 -9
  14. package/dist/services/transactions/transactionUtils.d.ts.map +1 -1
  15. package/dist/services/transactions/transactionUtils.js +3 -2
  16. package/dist/solautoPosition/marginfiSolautoPositionEx.d.ts +5 -0
  17. package/dist/solautoPosition/marginfiSolautoPositionEx.d.ts.map +1 -1
  18. package/dist/solautoPosition/marginfiSolautoPositionEx.js +15 -2
  19. package/dist/solautoPosition/solautoPositionEx.d.ts +2 -0
  20. package/dist/solautoPosition/solautoPositionEx.d.ts.map +1 -1
  21. package/dist/solautoPosition/utils.js +1 -1
  22. package/dist/types/accounts.d.ts +0 -1
  23. package/dist/types/accounts.d.ts.map +1 -1
  24. package/dist/utils/generalUtils.d.ts +1 -0
  25. package/dist/utils/generalUtils.d.ts.map +1 -1
  26. package/dist/utils/generalUtils.js +10 -0
  27. package/dist/utils/index.d.ts +1 -0
  28. package/dist/utils/index.d.ts.map +1 -1
  29. package/dist/utils/index.js +1 -0
  30. package/dist/utils/marginfiUtils.d.ts +7 -2
  31. package/dist/utils/marginfiUtils.d.ts.map +1 -1
  32. package/dist/utils/marginfiUtils.js +44 -11
  33. package/dist/utils/pythUtils.d.ts +21 -0
  34. package/dist/utils/pythUtils.d.ts.map +1 -0
  35. package/dist/utils/pythUtils.js +67 -0
  36. package/dist/utils/solautoUtils.js +1 -1
  37. package/local/txSandbox.ts +3 -3
  38. package/local/updateMarginfiLUT.ts +9 -15
  39. package/package.json +1 -1
  40. package/src/constants/marginfiAccounts.ts +13 -39
  41. package/src/constants/pythConstants.ts +8 -0
  42. package/src/services/flashLoans/marginfiFlProvider.ts +9 -9
  43. package/src/services/solauto/solautoClient.ts +6 -6
  44. package/src/services/solauto/solautoMarginfiClient.ts +5 -11
  45. package/src/services/transactions/transactionUtils.ts +1 -1
  46. package/src/solautoPosition/marginfiSolautoPositionEx.ts +22 -3
  47. package/src/solautoPosition/solautoPositionEx.ts +2 -0
  48. package/src/solautoPosition/utils.ts +1 -1
  49. package/src/types/accounts.ts +0 -1
  50. package/src/utils/generalUtils.ts +12 -0
  51. package/src/utils/index.ts +1 -0
  52. package/src/utils/marginfiUtils.ts +75 -17
  53. package/src/utils/pythUtils.ts +84 -0
  54. package/src/utils/solautoUtils.ts +1 -1
  55. package/tests/unit/accounts.ts +7 -13
  56. package/tests/unit/lookupTables.ts +27 -48
@@ -1,5 +1,13 @@
1
1
  import { NATIVE_MINT } from "@solana/spl-token";
2
2
  import * as tokens from "./tokenConstants";
3
+ import { PublicKey } from "@solana/web3.js";
4
+
5
+ export const PYTH_PUSH_PROGRAM = new PublicKey(
6
+ "pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT"
7
+ );
8
+
9
+ export const PYTH_SPONSORED_SHARD_ID = 0;
10
+ export const MARGINFI_SPONSORED_SHARD_ID = 3301;
3
11
 
4
12
  // https://pyth.network/developers/price-feed-ids#solana-stable
5
13
  export const PYTH_PRICE_FEED_IDS = {
@@ -29,6 +29,7 @@ import {
29
29
  fromBaseUnit,
30
30
  getBankLiquidityAvailableBaseUnit,
31
31
  getEmptyMarginfiAccountsByAuthority,
32
+ getMarginfiPriceOracle,
32
33
  getTokenAccount,
33
34
  rpcAccountCreated,
34
35
  safeGetPrice,
@@ -72,15 +73,15 @@ export class MarginfiFlProvider extends FlProviderBase {
72
73
  const bankAccounts = getMarginfiAccounts(this.programEnv).bankAccounts;
73
74
 
74
75
  const availableBanks: string[] = [];
75
- const checkIfUsable = (group: string, mint: PublicKey) => {
76
- if (Object.keys(bankAccounts[group]).includes(mint.toString())) {
77
- availableBanks.push(bankAccounts[group][mint.toString()].bank);
76
+ const checkIfUsable = (group: string, mint: string) => {
77
+ if (Object.keys(bankAccounts[group]).includes(mint)) {
78
+ availableBanks.push(bankAccounts[group][mint].bank);
78
79
  }
79
80
  };
80
81
 
81
82
  for (const group of Object.keys(bankAccounts)) {
82
- checkIfUsable(group, this.supplyMint);
83
- checkIfUsable(group, this.debtMint);
83
+ checkIfUsable(group, this.supplyMint.toString());
84
+ checkIfUsable(group, this.debtMint.toString());
84
85
  }
85
86
 
86
87
  const banks = await safeFetchAllBank(
@@ -301,11 +302,10 @@ export class MarginfiFlProvider extends FlProviderBase {
301
302
  flBankHadPrevBalance = true;
302
303
  }
303
304
 
304
- // TODO: Don't dynamically pull from bank until Marginfi sorts out their price oracle issues.
305
- // const bankData = await safeFetchBank(this.umi, publicKey(accounts.data.bank));
306
- // const priceOracle = bankData!.config.oracleKeys[0];
307
305
  const priceOracle = publicKey(
308
- findMarginfiAccounts(toWeb3JsPublicKey(x.bankPk)).priceOracle
306
+ await getMarginfiPriceOracle(this.umi, {
307
+ pk: toWeb3JsPublicKey(x.bankPk),
308
+ })
309
309
  );
310
310
 
311
311
  remainingAccounts.push(
@@ -205,12 +205,8 @@ export abstract class SolautoClient extends ReferralStateManager {
205
205
  return [
206
206
  this.authority,
207
207
  ...(this.authorityLutAddress ? [this.authorityLutAddress] : []),
208
- ...(toWeb3JsPublicKey(this.signer.publicKey).equals(this.authority)
209
- ? [this.signerSupplyTa]
210
- : []),
211
- ...(toWeb3JsPublicKey(this.signer.publicKey).equals(this.authority)
212
- ? [this.signerDebtTa]
213
- : []),
208
+ this.signerSupplyTa,
209
+ this.signerDebtTa,
214
210
  this.pos.publicKey,
215
211
  this.positionSupplyTa,
216
212
  this.positionDebtTa,
@@ -239,6 +235,10 @@ export abstract class SolautoClient extends ReferralStateManager {
239
235
  }
240
236
  | undefined
241
237
  > {
238
+ if (!toWeb3JsPublicKey(this.signer.publicKey).equals(this.authority)) {
239
+ return undefined;
240
+ }
241
+
242
242
  const existingLutAccounts = await this.fetchExistingAuthorityLutAccounts();
243
243
  if (
244
244
  this.lutAccountsToAdd().every((element) =>
@@ -32,6 +32,7 @@ import {
32
32
  hasFirstRebalance,
33
33
  } from "../../utils";
34
34
  import {
35
+ Bank,
35
36
  lendingAccountBorrow,
36
37
  lendingAccountDeposit,
37
38
  lendingAccountRepay,
@@ -113,19 +114,12 @@ export class SolautoMarginfiClient extends SolautoClient {
113
114
  this.pos.debtMint().toString()
114
115
  ]!;
115
116
 
116
- // TODO: Don't dynamically pull oracle from bank until Marginfi sorts out their price oracle issues.
117
- // const [supplyBank, debtBank] = await safeFetchAllBank(this.umi, [
118
- // publicKey(this.marginfiSupplyAccounts.bank),
119
- // publicKey(this.marginfiDebtAccounts.bank),
120
- // ]);
121
- // this.supplyPriceOracle = toWeb3JsPublicKey(supplyBank.config.oracleKeys[0]);
122
- // this.debtPriceOracle = toWeb3JsPublicKey(debtBank.config.oracleKeys[0]);
123
- this.supplyPriceOracle = new PublicKey(
124
- this.marginfiSupplyAccounts.priceOracle
125
- );
126
- this.debtPriceOracle = new PublicKey(this.marginfiDebtAccounts.priceOracle);
117
+ [this.supplyPriceOracle, this.debtPriceOracle] =
118
+ await this.pos.priceOracles();
127
119
 
128
120
  this.log("Marginfi account:", this.marginfiAccountPk.toString());
121
+ this.log("Supply price oracle:", this.supplyPriceOracle.toString());
122
+ this.log("Debt price oracle:", this.debtPriceOracle.toString());
129
123
  }
130
124
 
131
125
  defaultLookupTables(): string[] {
@@ -39,7 +39,6 @@ import {
39
39
  getTokenAccount,
40
40
  getTokenAccountData,
41
41
  isMarginfiClient,
42
- isMarginfiProgram,
43
42
  } from "../../utils";
44
43
  import {
45
44
  createMarginfiProgram,
@@ -56,6 +55,7 @@ import {
56
55
  JUPITER_PROGRAM_ID,
57
56
  } from "../../jupiter-sdk";
58
57
  import { TransactionItemInputs, BundleSimulationError } from "../../types";
58
+ import { isMarginfiProgram } from "../../constants";
59
59
 
60
60
  interface wSolTokenUsage {
61
61
  wSolTokenAccount: PublicKey;
@@ -13,11 +13,15 @@ import {
13
13
  fromBaseUnit,
14
14
  getBankLiquidityAvailableBaseUnit,
15
15
  getMarginfiAccountPositionState,
16
+ getMarginfiPriceOracle,
16
17
  } from "../utils";
17
18
  import { getMarginfiAccounts } from "../constants";
18
19
  import { SolautoPositionEx } from "./solautoPositionEx";
20
+ import { LendingPlatform } from "../generated";
19
21
 
20
22
  export class MarginfiSolautoPositionEx extends SolautoPositionEx {
23
+ lendingPlatform = LendingPlatform.Marginfi;
24
+
21
25
  private marginfiAccountData: MarginfiAccount | null = null;
22
26
  private supplyBank: Bank | null = null;
23
27
  private debtBank: Bank | null = null;
@@ -47,7 +51,7 @@ export class MarginfiSolautoPositionEx extends SolautoPositionEx {
47
51
  return this.lp;
48
52
  }
49
53
 
50
- async maxLtvAndLiqThresholdBps(): Promise<[number, number]> {
54
+ async getBanks(): Promise<Bank[]> {
51
55
  if (!this.supplyBank || !this.debtBank) {
52
56
  const group = (await this.lendingPool()).toString();
53
57
  const bankAccounts = getMarginfiAccounts(this.lpEnv).bankAccounts;
@@ -60,10 +64,25 @@ export class MarginfiSolautoPositionEx extends SolautoPositionEx {
60
64
  ]);
61
65
  }
62
66
 
67
+ return [this.supplyBank!, this.debtBank!];
68
+ }
69
+
70
+ async priceOracles(): Promise<PublicKey[]> {
71
+ const [supplyBank, debtBank] = await this.getBanks();
72
+
73
+ return await Promise.all([
74
+ getMarginfiPriceOracle(this.umi, { data: supplyBank }),
75
+ getMarginfiPriceOracle(this.umi, { data: debtBank }),
76
+ ]);
77
+ }
78
+
79
+ async maxLtvAndLiqThresholdBps(): Promise<[number, number]> {
80
+ const [supplyBank, debtBank] = await this.getBanks();
81
+
63
82
  const [supplyPrice] = await fetchTokenPrices([this.supplyMint()]);
64
83
  const [maxLtvBps, liqThresholdBps] = calcMarginfiMaxLtvAndLiqThresholdBps(
65
- this.supplyBank,
66
- this.debtBank,
84
+ supplyBank,
85
+ debtBank,
67
86
  supplyPrice
68
87
  );
69
88
 
@@ -67,6 +67,7 @@ interface PositionExArgs {
67
67
  }
68
68
 
69
69
  export abstract class SolautoPositionEx {
70
+ public lendingPlatform!: LendingPlatform;
70
71
  public umi!: Umi;
71
72
  public publicKey!: PublicKey;
72
73
  protected _data!: SolautoPositionExData;
@@ -226,6 +227,7 @@ export abstract class SolautoPositionEx {
226
227
  }
227
228
 
228
229
  abstract maxLtvAndLiqThresholdBps(): Promise<[number, number]>;
230
+ abstract priceOracles(): Promise<PublicKey[]>;
229
231
  abstract supplyLiquidityAvailable(): number;
230
232
 
231
233
  sufficientLiquidityToBoost() {
@@ -41,7 +41,7 @@ export async function getPositionExBulk(
41
41
  umi: Umi,
42
42
  publicKeys: PublicKey[]
43
43
  ): Promise<SolautoPositionEx[]> {
44
- const batches = getBatches(publicKeys, 30);
44
+ const batches = getBatches(publicKeys, 50);
45
45
 
46
46
  const data = (
47
47
  await Promise.all(
@@ -2,5 +2,4 @@ export interface MarginfiAssetAccounts {
2
2
  bank: string;
3
3
  liquidityVault: string;
4
4
  vaultAuthority: string;
5
- priceOracle: string;
6
5
  }
@@ -184,3 +184,15 @@ export async function customRpcCall(umi: Umi, method: string, params?: any) {
184
184
  return data;
185
185
  }
186
186
  }
187
+
188
+ export function u16ToArrayBufferLE(value: number): Uint8Array {
189
+ // Create a buffer of 2 bytes
190
+ const buffer = new ArrayBuffer(2);
191
+ const dataView = new DataView(buffer);
192
+
193
+ // Set the Uint16 value in little-endian order
194
+ dataView.setUint16(0, value, true);
195
+
196
+ // Return the buffer
197
+ return new Uint8Array(buffer);
198
+ }
@@ -8,4 +8,5 @@ export * from "./solautoUtils";
8
8
  export * from "./solanaUtils";
9
9
  export * from "./stringUtils";
10
10
  export * from "./priceUtils";
11
+ export * from "./pythUtils";
11
12
  export * from "./switchboardUtils";
@@ -9,20 +9,22 @@ import { PositionState, PositionTokenState } from "../generated";
9
9
  import {
10
10
  ALL_SUPPORTED_TOKENS,
11
11
  getMarginfiAccounts,
12
- MARGINFI_PROD_PROGRAM,
13
- MARGINFI_STAGING_PROGRAM,
14
- MarginfiAccountsMap,
12
+ MARGINFI_SPONSORED_SHARD_ID,
13
+ MarginfiBankAccountsMap,
14
+ PYTH_SPONSORED_SHARD_ID,
15
15
  TOKEN_INFO,
16
16
  USD_DECIMALS,
17
17
  } from "../constants";
18
18
  import {
19
19
  Bank,
20
20
  deserializeMarginfiAccount,
21
+ fetchBank,
21
22
  getMarginfiAccountSize,
22
23
  getMarginfiErrorFromCode,
23
24
  getMarginfiErrorFromName,
24
25
  MarginfiAccount,
25
26
  OracleSetup,
27
+ safeFetchAllBank,
26
28
  safeFetchBank,
27
29
  safeFetchMarginfiAccount,
28
30
  } from "../marginfi-sdk";
@@ -38,22 +40,15 @@ import {
38
40
  toBps,
39
41
  } from "./numberUtils";
40
42
  import { getTokenAccountData } from "./accountUtils";
41
-
42
- export function getMarginfiProgram(env: ProgramEnv) {
43
- return env === "Prod" ? MARGINFI_PROD_PROGRAM : MARGINFI_STAGING_PROGRAM;
44
- }
45
-
46
- export function isMarginfiProgram(programId: PublicKey) {
47
- return (
48
- programId.equals(MARGINFI_PROD_PROGRAM) ||
49
- programId.equals(MARGINFI_STAGING_PROGRAM)
50
- );
51
- }
43
+ import {
44
+ getMostUpToDatePythOracle,
45
+ getPythPushOracleAddress,
46
+ } from "./pythUtils";
52
47
 
53
48
  export function createDynamicMarginfiProgram(env?: ProgramEnv): Program {
54
49
  return {
55
50
  name: "marginfi",
56
- publicKey: publicKey(getMarginfiProgram(env ?? "Prod")),
51
+ publicKey: publicKey(getMarginfiAccounts(env ?? "Prod").program),
57
52
  getErrorFromCode(code: number, cause?: Error) {
58
53
  return getMarginfiErrorFromCode(code, this, cause);
59
54
  },
@@ -77,18 +72,81 @@ export function umiWithMarginfiProgram(umi: Umi, marginfiEnv?: ProgramEnv) {
77
72
  });
78
73
  }
79
74
 
75
+ export async function getAllBankRelatedAccounts(
76
+ umi: Umi,
77
+ bankAccountsMap: MarginfiBankAccountsMap
78
+ ): Promise<PublicKey[]> {
79
+ const banks = Object.values(bankAccountsMap).flatMap((group) =>
80
+ Object.values(group).map((accounts) => accounts.bank)
81
+ );
82
+ const banksData = await safeFetchAllBank(
83
+ umi,
84
+ banks.map((x) => publicKey(x))
85
+ );
86
+
87
+ const oracles = banksData
88
+ .map((bank) => {
89
+ const oracleKey = toWeb3JsPublicKey(bank.config.oracleKeys[0]);
90
+ return bank.config.oracleSetup === OracleSetup.PythPushOracle
91
+ ? [
92
+ getPythPushOracleAddress(oracleKey, PYTH_SPONSORED_SHARD_ID),
93
+ getPythPushOracleAddress(oracleKey, MARGINFI_SPONSORED_SHARD_ID),
94
+ ]
95
+ : [oracleKey];
96
+
97
+ })
98
+ .flat()
99
+ .map((x) => x.toString());
100
+
101
+ const otherAccounts = Object.entries(bankAccountsMap).flatMap(
102
+ ([groupName, tokenMap]) =>
103
+ Object.values(tokenMap).flatMap((accounts) => [
104
+ groupName,
105
+ accounts.liquidityVault,
106
+ accounts.vaultAuthority,
107
+ ])
108
+ );
109
+
110
+ return Array.from(new Set([...banks, ...oracles, ...otherAccounts]))
111
+ .filter((x) => x !== PublicKey.default.toString())
112
+ .map((x) => new PublicKey(x));
113
+ }
114
+
80
115
  export async function fetchBankAddresses(umi: Umi, bankPk: PublicKey) {
81
- const bank = await safeFetchBank(umi, fromWeb3JsPublicKey(bankPk));
116
+ const bank = await fetchBank(umi, fromWeb3JsPublicKey(bankPk));
82
117
  const liquidityVault = toWeb3JsPublicKey(bank!.liquidityVault);
83
118
  const vaultAuthority = (await getTokenAccountData(umi, liquidityVault))
84
119
  ?.owner;
120
+ const priceOracle = await getMarginfiPriceOracle(umi, { data: bank });
121
+
85
122
  return {
86
123
  bank: bankPk,
87
124
  liquidityVault,
88
125
  vaultAuthority,
126
+ priceOracle,
89
127
  };
90
128
  }
91
129
 
130
+ export async function getMarginfiPriceOracle(
131
+ umi: Umi,
132
+ bank: { pk?: PublicKey; data?: Bank }
133
+ ) {
134
+ if (!bank.data) {
135
+ bank.data = await fetchBank(umi, fromWeb3JsPublicKey(bank.pk!));
136
+ }
137
+
138
+ const oracleKey = toWeb3JsPublicKey(bank.data.config.oracleKeys[0]);
139
+ const priceOracle =
140
+ bank.data.config.oracleSetup === OracleSetup.PythPushOracle
141
+ ? await getMostUpToDatePythOracle(umi, [
142
+ getPythPushOracleAddress(oracleKey, PYTH_SPONSORED_SHARD_ID),
143
+ getPythPushOracleAddress(oracleKey, MARGINFI_SPONSORED_SHARD_ID),
144
+ ])
145
+ : oracleKey;
146
+
147
+ return priceOracle;
148
+ }
149
+
92
150
  interface AllMarginfiAssetAccounts extends MarginfiAssetAccounts {
93
151
  mint: PublicKey;
94
152
  }
@@ -96,7 +154,7 @@ interface AllMarginfiAssetAccounts extends MarginfiAssetAccounts {
96
154
  export function findMarginfiAccounts(
97
155
  bank: PublicKey
98
156
  ): AllMarginfiAssetAccounts {
99
- const search = (bankAccounts: MarginfiAccountsMap) => {
157
+ const search = (bankAccounts: MarginfiBankAccountsMap) => {
100
158
  for (const group in bankAccounts) {
101
159
  for (const key in bankAccounts[group]) {
102
160
  const account = bankAccounts[group][key];
@@ -0,0 +1,84 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import { PYTH_PUSH_PROGRAM } from "../constants";
3
+ import { u16ToArrayBufferLE, zip } from "./generalUtils";
4
+ import * as borsh from "borsh";
5
+ import { Umi } from "@metaplex-foundation/umi";
6
+ import { fromWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
7
+
8
+ type PriceUpdateV2 = {
9
+ writeAuthority: Buffer;
10
+ verificationLevel: number;
11
+ priceMessage: {
12
+ feedId: Buffer;
13
+ price: bigint;
14
+ conf: bigint;
15
+ exponent: number;
16
+ publishTime: bigint;
17
+ prevPublishTime: bigint;
18
+ emaPrice: bigint;
19
+ emaConf: bigint;
20
+ };
21
+ };
22
+
23
+ const priceUpdateV2Schema = {
24
+ struct: {
25
+ writeAuthority: {
26
+ array: { type: "u8", len: 32 },
27
+ },
28
+ verificationLevel: "u8",
29
+ priceMessage: {
30
+ struct: {
31
+ feedId: { array: { type: "u8", len: 32 } },
32
+ price: "i64",
33
+ conf: "u64",
34
+ exponent: "i32",
35
+ publishTime: "i64",
36
+ prevPublishTime: "i64",
37
+ emaPrice: "i64",
38
+ emaConf: "u64",
39
+ },
40
+ },
41
+ postedSlot: "u64",
42
+ },
43
+ };
44
+
45
+ export function parsePriceInfo(data: Uint8Array): PriceUpdateV2 {
46
+ let decoded: PriceUpdateV2 = borsh.deserialize(
47
+ priceUpdateV2Schema,
48
+ data
49
+ ) as any;
50
+ return decoded;
51
+ }
52
+
53
+ export async function getMostUpToDatePythOracle(
54
+ umi: Umi,
55
+ oracleKeys: PublicKey[]
56
+ ) {
57
+ const oracles = zip(
58
+ oracleKeys,
59
+ (
60
+ await umi.rpc.getAccounts(
61
+ oracleKeys.map((x) => fromWeb3JsPublicKey(x)),
62
+ { commitment: "confirmed" }
63
+ )
64
+ ).map((x) => (x.exists ? parsePriceInfo(x!.data.slice(8)) : undefined))
65
+ ).sort(
66
+ (a, b) =>
67
+ Number(b[1]?.priceMessage.publishTime ?? 0) -
68
+ Number(a[1]?.priceMessage.publishTime ?? 0)
69
+ );
70
+
71
+ return oracles[0][0];
72
+ }
73
+
74
+ export function getPythPushOracleAddress(
75
+ feedId: PublicKey,
76
+ shardId: number,
77
+ programId: PublicKey = PYTH_PUSH_PROGRAM
78
+ ): PublicKey {
79
+ const shardBytes = u16ToArrayBufferLE(shardId);
80
+ return PublicKey.findProgramAddressSync(
81
+ [shardBytes, feedId.toBuffer()],
82
+ programId
83
+ )[0];
84
+ }
@@ -453,7 +453,7 @@ export function getClient(
453
453
  export function isMarginfiClient(
454
454
  client: SolautoClient
455
455
  ): client is SolautoMarginfiClient {
456
- return client.lendingPlatform == LendingPlatform.Marginfi;
456
+ return client.lendingPlatform === LendingPlatform.Marginfi;
457
457
  }
458
458
  // TODO: PF
459
459
 
@@ -6,21 +6,17 @@ import { toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
6
6
  import {
7
7
  ALL_SUPPORTED_TOKENS,
8
8
  TOKEN_INFO,
9
- MARGINFI_ACCOUNTS,
10
9
  SOLAUTO_FEES_WALLET,
11
10
  SOLAUTO_MANAGER,
12
11
  LOCAL_IRONFORGE_API_URL,
13
- } from "../../src/constants";
14
- import {
12
+ getMarginfiAccounts,
15
13
  getSolanaRpcConnection,
16
14
  getEmptyMarginfiAccountsByAuthority,
17
15
  getTokenAccount,
18
- } from "../../src/utils";
16
+ } from "../../src";
19
17
 
20
18
  async function hasTokenAccounts(wallet: PublicKey) {
21
- let [_, umi] = getSolanaRpcConnection(
22
- LOCAL_IRONFORGE_API_URL
23
- );
19
+ let [_, umi] = getSolanaRpcConnection(LOCAL_IRONFORGE_API_URL);
24
20
 
25
21
  const tokenAccounts = await umi.rpc.getAccounts(
26
22
  ALL_SUPPORTED_TOKENS.map((x) =>
@@ -45,17 +41,15 @@ describe("Assert Solauto fee token accounts are created", async () => {
45
41
  });
46
42
 
47
43
  it("ISM accounts for every supported Marginfi group", async () => {
48
- let [_, umi] = getSolanaRpcConnection(
49
- LOCAL_IRONFORGE_API_URL
50
- );
44
+ let [_, umi] = getSolanaRpcConnection(LOCAL_IRONFORGE_API_URL);
51
45
 
52
46
  const ismAccounts = await getEmptyMarginfiAccountsByAuthority(
53
47
  umi,
54
48
  SOLAUTO_MANAGER
55
49
  );
56
- const supportedMarginfiGroups = Object.keys(MARGINFI_ACCOUNTS).map(
57
- (x) => new PublicKey(x)
58
- );
50
+ const supportedMarginfiGroups = Object.keys(
51
+ getMarginfiAccounts("Prod").bankAccounts
52
+ ).map((x) => new PublicKey(x));
59
53
  const missingIsmAccounts = supportedMarginfiGroups.filter(
60
54
  (group) =>
61
55
  !ismAccounts.find((x) => group.equals(toWeb3JsPublicKey(x.group)))
@@ -1,64 +1,43 @@
1
1
  import { describe, it } from "mocha";
2
- import { PublicKey } from "@solana/web3.js";
3
2
  import {
3
+ getMarginfiAccounts,
4
4
  LOCAL_IRONFORGE_API_URL,
5
- MARGINFI_ACCOUNTS,
6
- MARGINFI_ACCOUNTS_LOOKUP_TABLE,
7
5
  SOLAUTO_MANAGER,
8
- } from "../../src/constants";
9
- import {
6
+ getAllBankRelatedAccounts,
10
7
  getEmptyMarginfiAccountsByAuthority,
11
8
  getSolanaRpcConnection,
12
- } from "../../src/utils";
9
+ ProgramEnv,
10
+ } from "../../src";
13
11
 
14
- const [conn, umi] = getSolanaRpcConnection(
15
- LOCAL_IRONFORGE_API_URL
16
- );
12
+ const [conn, umi] = getSolanaRpcConnection(LOCAL_IRONFORGE_API_URL);
17
13
 
18
- describe("Assert lookup tables up-to-date", async () => {
19
- it("marginfi accounts LUT should have everything", async () => {
20
- const lookupTable = await conn.getAddressLookupTable(
21
- new PublicKey(MARGINFI_ACCOUNTS_LOOKUP_TABLE)
22
- );
23
- if (lookupTable === null) {
24
- throw new Error("Lookup table not found");
25
- }
14
+ async function checkLookupTableAccounts(programEnv: ProgramEnv) {
15
+ const data = getMarginfiAccounts(programEnv);
16
+ const lookupTable = await conn.getAddressLookupTable(data.lookupTable);
17
+ if (lookupTable === null) {
18
+ throw new Error("Lookup table not found");
19
+ }
26
20
 
27
- const ismAccounts = await getEmptyMarginfiAccountsByAuthority(
28
- umi,
29
- SOLAUTO_MANAGER
30
- );
21
+ const ismAccounts = (
22
+ await getEmptyMarginfiAccountsByAuthority(umi, SOLAUTO_MANAGER)
23
+ ).map((x) => x.publicKey.toString());
31
24
 
32
- const existingAccounts =
33
- lookupTable.value?.state.addresses.map((x) => x.toString()) ?? [];
25
+ const bankAccounts = (
26
+ await getAllBankRelatedAccounts(umi, data.bankAccounts)
27
+ ).map((x) => x.toString());
34
28
 
35
- for (const group in MARGINFI_ACCOUNTS) {
36
- for (const key in MARGINFI_ACCOUNTS[group]) {
37
- if (key === PublicKey.default.toString()) {
38
- continue;
39
- }
29
+ const accountsRequired = [...ismAccounts, ...bankAccounts];
40
30
 
41
- const groupIsmAccounts = ismAccounts
42
- .filter((x) => x.group.toString() === group)
43
- .map((x) => x.publicKey.toString());
44
- if (groupIsmAccounts.length === 0) {
45
- throw new Error(`Missing ISM account for group: ${group}`);
46
- }
31
+ const existingAccounts =
32
+ lookupTable.value?.state.addresses.map((x) => x.toString()) ?? [];
47
33
 
48
- const accounts = MARGINFI_ACCOUNTS[group][key];
49
- const addresses = [
50
- group,
51
- accounts.bank,
52
- accounts.liquidityVault,
53
- accounts.vaultAuthority,
54
- accounts.priceOracle,
55
- ...groupIsmAccounts,
56
- ];
34
+ if (accountsRequired.find((x) => !existingAccounts.includes(x.toString()))) {
35
+ throw new Error("Marginfi accounts lookup table missing an account");
36
+ }
37
+ }
57
38
 
58
- if (addresses.find((x) => !existingAccounts.includes(x.toString()))) {
59
- throw new Error("Marginfi accounts lookup table missing an account");
60
- }
61
- }
62
- }
39
+ describe("Assert lookup tables up-to-date", async () => {
40
+ it("marginfi accounts LUT should have everything", async () => {
41
+ await checkLookupTableAccounts("Prod");
63
42
  });
64
43
  });