@exponent-labs/generic-sy-sdk 0.9.21 → 0.9.22

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 (2) hide show
  1. package/package.json +9 -9
  2. package/src/index.ts +117 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exponent-labs/generic-sy-sdk",
3
- "version": "0.9.21",
3
+ "version": "0.9.22",
4
4
  "main": "build/index.js",
5
5
  "types": "build/index.d.ts",
6
6
  "license": "AGPL-3.0",
@@ -12,14 +12,14 @@
12
12
  "@coral-xyz/anchor": "^0.31.0",
13
13
  "@solana/spl-stake-pool": "1.1.8",
14
14
  "@solana/spl-token": "0.4.6",
15
- "@exponent-labs/exponent-admin-pda": "0.9.21",
16
- "@exponent-labs/exponent-fetcher": "0.9.21",
17
- "@exponent-labs/exponent-tranching-idl": "0.9.21",
18
- "@exponent-labs/exponent-types": "0.9.21",
19
- "@exponent-labs/fragmetric-pda": "0.9.21",
20
- "@exponent-labs/generic-sy-idl": "0.9.21",
21
- "@exponent-labs/generic-sy-pda": "0.9.21",
22
- "@exponent-labs/precise-number": "0.9.21"
15
+ "@exponent-labs/exponent-admin-pda": "0.9.22",
16
+ "@exponent-labs/exponent-fetcher": "0.9.22",
17
+ "@exponent-labs/exponent-tranching-idl": "0.9.22",
18
+ "@exponent-labs/exponent-types": "0.9.22",
19
+ "@exponent-labs/fragmetric-pda": "0.9.22",
20
+ "@exponent-labs/generic-sy-idl": "0.9.22",
21
+ "@exponent-labs/generic-sy-pda": "0.9.22",
22
+ "@exponent-labs/precise-number": "0.9.22"
23
23
  },
24
24
  "devDependencies": {
25
25
  "typescript": "5.4.5"
package/src/index.ts CHANGED
@@ -47,6 +47,67 @@ import { fetchGlowVaultRate } from "./interfaces/glowVault"
47
47
  import { SyInitializeConfig, SyTokenMetadata } from "./types"
48
48
  import { MyWallet } from "./utils"
49
49
 
50
+ const GET_STATE_DISCRIMINATOR = Buffer.from([7])
51
+
52
+ async function fetchOnChainSyRate({
53
+ connection,
54
+ programId,
55
+ meta,
56
+ mintSy,
57
+ tokenSyEscrow,
58
+ remainingAccounts,
59
+ }: {
60
+ connection: web3.Connection
61
+ programId: web3.PublicKey
62
+ meta: web3.PublicKey
63
+ mintSy: web3.PublicKey
64
+ tokenSyEscrow: web3.PublicKey
65
+ remainingAccounts: web3.AccountMeta[]
66
+ }): Promise<number> {
67
+ const instruction = new web3.TransactionInstruction({
68
+ programId,
69
+ keys: [
70
+ { pubkey: meta, isSigner: false, isWritable: true },
71
+ { pubkey: mintSy, isSigner: false, isWritable: false },
72
+ { pubkey: tokenSyEscrow, isSigner: false, isWritable: false },
73
+ ...remainingAccounts,
74
+ ],
75
+ data: GET_STATE_DISCRIMINATOR,
76
+ })
77
+ const [feePayer, { blockhash }] = await Promise.all([
78
+ connection.getSlotLeader("confirmed"),
79
+ connection.getLatestBlockhash("confirmed"),
80
+ ])
81
+ const message = new web3.TransactionMessage({
82
+ payerKey: new web3.PublicKey(feePayer),
83
+ recentBlockhash: blockhash,
84
+ instructions: [instruction],
85
+ }).compileToV0Message()
86
+ const simulation = await connection.simulateTransaction(new web3.VersionedTransaction(message), {
87
+ commitment: "confirmed",
88
+ replaceRecentBlockhash: true,
89
+ sigVerify: false,
90
+ })
91
+
92
+ if (simulation.value.err) {
93
+ const logs = simulation.value.logs?.join("\n") ?? "No simulation logs"
94
+ throw new Error(`Generic Standard get_state simulation failed: ${JSON.stringify(simulation.value.err)}\n${logs}`)
95
+ }
96
+
97
+ const returnData = simulation.value.returnData
98
+ if (!returnData || returnData.programId !== programId.toBase58()) {
99
+ throw new Error("Generic Standard get_state returned invalid program data")
100
+ }
101
+
102
+ const data = Buffer.from(returnData.data[0], "base64")
103
+ if (data.length < 32) {
104
+ throw new Error("Generic Standard get_state return data is too short")
105
+ }
106
+
107
+ const exchangeRate = Array.from({ length: 4 }, (_, index) => new BN(data.subarray(index * 8, (index + 1) * 8), "le"))
108
+ return Number(PreciseNumber.fromRaw(exchangeRate).valueString)
109
+ }
110
+
50
111
  /**
51
112
  * Create a custom updateStakePoolBalance instruction using dynamic program ID
52
113
  */
@@ -126,6 +187,7 @@ export enum InterfaceType {
126
187
  SolsticeGlamVault = 18,
127
188
  ExponentTranching = 19,
128
189
  GlowVault = 20,
190
+ LoopscaleVaultLp = 21,
129
191
  }
130
192
 
131
193
  export function getInterfaceTypeIndex(interfaceType: InterfaceTypeGeneric): InterfaceType {
@@ -150,6 +212,7 @@ export function getInterfaceTypeIndex(interfaceType: InterfaceTypeGeneric): Inte
150
212
  if ("solsticeGlamVault" in interfaceType) return InterfaceType.SolsticeGlamVault
151
213
  if ("exponentTranching" in interfaceType) return InterfaceType.ExponentTranching
152
214
  if ("glowVault" in interfaceType) return InterfaceType.GlowVault
215
+ if ("loopscaleVaultLp" in interfaceType) return InterfaceType.LoopscaleVaultLp
153
216
 
154
217
  throw new Error("Unsupported interface type")
155
218
  }
@@ -218,6 +281,8 @@ export function getInterfaceTypeObj(
218
281
  return { exponentTranching: {} }
219
282
  case InterfaceType.GlowVault:
220
283
  return { glowVault: { padding: [] } }
284
+ case InterfaceType.LoopscaleVaultLp:
285
+ return { loopscaleVaultLp: { padding: [] } }
221
286
  default:
222
287
  throw new Error(`Unsupported interface type: ${interfaceType}`)
223
288
  }
@@ -281,6 +346,9 @@ export function getInterfaceTypeFromString(interfaceType: string): InterfaceType
281
346
  return { exponentTranching: {} }
282
347
  case "glow-vault":
283
348
  return { glowVault: { padding: [] } }
349
+ case "loopscale-vault":
350
+ case "loopscale-vault-lp":
351
+ return { loopscaleVaultLp: { padding: [] } }
284
352
  default:
285
353
  throw new Error(`Unsupported interface type: ${interfaceType}`)
286
354
  }
@@ -313,14 +381,22 @@ export class GenericSySdk {
313
381
  this.syPda = new GenericSyPda(programId, interfaceIndex)
314
382
  }
315
383
 
316
- private static async calculateSyRate(
317
- account: GenericSyMetaAccount,
318
- interfaceType: InterfaceTypeGeneric,
319
- cnx: web3.Connection,
320
- ): Promise<{
384
+ private static async calculateSyRate({
385
+ account,
386
+ cnx,
387
+ syMetaAddress,
388
+ genericStandardProgramId,
389
+ }: {
390
+ account: GenericSyMetaAccount
391
+ cnx: web3.Connection
392
+ syMetaAddress: web3.PublicKey
393
+ genericStandardProgramId: web3.PublicKey
394
+ }): Promise<{
321
395
  syRate: number
322
396
  additionalData?: AdditionalDataGeneric
323
397
  }> {
398
+ const interfaceType = getGenericSyMetaInterfaceType(account)
399
+
324
400
  if ("pyth" in interfaceType) {
325
401
  const syRate = Number(PreciseNumber.fromRaw(account.index[0]).valueString)
326
402
  return { syRate: syRate }
@@ -554,6 +630,28 @@ export class GenericSySdk {
554
630
  expectedShareMint: account.yieldBearingMint,
555
631
  })
556
632
  return { syRate }
633
+ } else if ("loopscaleVaultLp" in interfaceType) {
634
+ if (account.interfaceAccounts.length !== 3) {
635
+ throw new Error("Loopscale Vault LP interface requires exactly three accounts")
636
+ }
637
+
638
+ const syRate = await fetchOnChainSyRate({
639
+ connection: cnx,
640
+ programId: genericStandardProgramId,
641
+ meta: syMetaAddress,
642
+ mintSy: account.mintSy,
643
+ tokenSyEscrow: account.tokenSyEscrow,
644
+ remainingAccounts: account.interfaceAccounts
645
+ .map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
646
+ .concat(
647
+ account.emissions.map((emission) => ({
648
+ pubkey: emission.escrowAccount,
649
+ isSigner: false,
650
+ isWritable: false,
651
+ })),
652
+ ),
653
+ })
654
+ return { syRate }
557
655
  } else {
558
656
  return { syRate: 1 }
559
657
  }
@@ -581,11 +679,12 @@ export class GenericSySdk {
581
679
  yieldBearingMint,
582
680
  })
583
681
 
584
- const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
682
+ const { syRate, additionalData } = await GenericSySdk.calculateSyRate({
585
683
  account,
586
- getGenericSyMetaInterfaceType(account),
587
684
  cnx,
588
- )
685
+ syMetaAddress: selfAddress,
686
+ genericStandardProgramId,
687
+ })
589
688
 
590
689
  const state: GenericSyState = {
591
690
  selfAddress,
@@ -614,11 +713,12 @@ export class GenericSySdk {
614
713
  const account = await fetcher.fetchGenericSyMeta(syMetaAddress)
615
714
  const tokenProgramBase = (await cnx.getAccountInfo(account.yieldBearingMint))?.owner
616
715
 
617
- const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
716
+ const { syRate, additionalData } = await GenericSySdk.calculateSyRate({
618
717
  account,
619
- getGenericSyMetaInterfaceType(account),
620
718
  cnx,
621
- )
719
+ syMetaAddress,
720
+ genericStandardProgramId,
721
+ })
622
722
 
623
723
  const state: GenericSyState = {
624
724
  selfAddress: syMetaAddress,
@@ -633,14 +733,16 @@ export class GenericSySdk {
633
733
 
634
734
  /** Reload the state of the account */
635
735
  async reload(cnx: web3.Connection) {
636
- const fetcher = new ExponentFetcher({ connection: cnx, genericStandardProgramId: this.program.programId })
736
+ const genericStandardProgramId = this.syPda.programId
737
+ const fetcher = new ExponentFetcher({ connection: cnx, genericStandardProgramId })
637
738
  const account = await fetcher.fetchGenericSyMeta(this.state.selfAddress)
638
739
  this.state.account = account
639
- const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
740
+ const { syRate, additionalData } = await GenericSySdk.calculateSyRate({
640
741
  account,
641
- getGenericSyMetaInterfaceType(account),
642
742
  cnx,
643
- )
743
+ syMetaAddress: this.state.selfAddress,
744
+ genericStandardProgramId,
745
+ })
644
746
  this.state.syRate = syRate
645
747
  this.state.additionalData = additionalData
646
748
  }