@exponent-labs/generic-sy-sdk 0.9.19 → 0.9.21
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.
- package/build/index.d.ts +16 -2
- package/build/index.js +160 -207
- package/build/index.js.map +1 -1
- package/build/interfaces/exponentTranching.d.ts +12 -0
- package/build/interfaces/exponentTranching.js +75 -0
- package/build/interfaces/exponentTranching.js.map +1 -0
- package/build/interfaces/glowVault.d.ts +7 -0
- package/build/interfaces/glowVault.js +46 -0
- package/build/interfaces/glowVault.js.map +1 -0
- package/package.json +10 -10
- package/src/index.ts +179 -159
- package/src/interfaces/exponentTranching.ts +125 -0
- package/src/interfaces/glowVault.ts +55 -0
- package/tsconfig.json +3 -0
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
5
5
|
TOKEN_2022_PROGRAM_ID,
|
|
6
6
|
TOKEN_PROGRAM_ID,
|
|
7
|
+
createAssociatedTokenAccountIdempotentInstruction,
|
|
7
8
|
getAssociatedTokenAddressSync,
|
|
8
9
|
} from "@solana/spl-token"
|
|
9
10
|
|
|
@@ -30,12 +31,19 @@ import {
|
|
|
30
31
|
GenericSyState,
|
|
31
32
|
Hook,
|
|
32
33
|
InterfaceTypeGeneric,
|
|
34
|
+
getGenericSyMetaInitInterfaceType,
|
|
35
|
+
getGenericSyMetaInterfaceType,
|
|
33
36
|
} from "@exponent-labs/exponent-types"
|
|
34
37
|
import { FRAGMETRIC_PROGRAM_ID, FragmetricPda } from "@exponent-labs/fragmetric-pda"
|
|
35
38
|
import { PROGRAM_ID as GENERIC_STANDARD_PROGRAM_ID, GenericStandard, IDL } from "@exponent-labs/generic-sy-idl"
|
|
36
39
|
import { GenericSyPda } from "@exponent-labs/generic-sy-pda"
|
|
37
40
|
import { PreciseNumber } from "@exponent-labs/precise-number"
|
|
38
41
|
|
|
42
|
+
import {
|
|
43
|
+
buildExponentTranchingUpdateMarketInstruction,
|
|
44
|
+
fetchExponentTranchingRate,
|
|
45
|
+
} from "./interfaces/exponentTranching"
|
|
46
|
+
import { fetchGlowVaultRate } from "./interfaces/glowVault"
|
|
39
47
|
import { SyInitializeConfig, SyTokenMetadata } from "./types"
|
|
40
48
|
import { MyWallet } from "./utils"
|
|
41
49
|
|
|
@@ -86,48 +94,7 @@ async function loadAccountState(
|
|
|
86
94
|
genericStandardProgramId: web3.PublicKey,
|
|
87
95
|
interfaceType: InterfaceTypeGeneric,
|
|
88
96
|
) {
|
|
89
|
-
|
|
90
|
-
if ("pyth" in interfaceType) {
|
|
91
|
-
interfaceIndex = InterfaceType.Pyth
|
|
92
|
-
} else if ("splStakePool" in interfaceType) {
|
|
93
|
-
interfaceIndex = InterfaceType.SplStakePool
|
|
94
|
-
} else if ("one" in interfaceType) {
|
|
95
|
-
interfaceIndex = InterfaceType.One
|
|
96
|
-
} else if ("fragmetric" in interfaceType) {
|
|
97
|
-
interfaceIndex = InterfaceType.Fragmetric
|
|
98
|
-
} else if ("meteora" in interfaceType) {
|
|
99
|
-
interfaceIndex = InterfaceType.Meteora
|
|
100
|
-
} else if ("sanctum" in interfaceType) {
|
|
101
|
-
interfaceIndex = InterfaceType.Sanctum
|
|
102
|
-
} else if ("fragmetricSupportedAsset" in interfaceType) {
|
|
103
|
-
interfaceIndex = InterfaceType.FragmetricSupportedAsset
|
|
104
|
-
} else if ("jupiterPerps" in interfaceType) {
|
|
105
|
-
interfaceIndex = InterfaceType.JupiterPerps
|
|
106
|
-
} else if ("adrena" in interfaceType) {
|
|
107
|
-
interfaceIndex = InterfaceType.Adrena
|
|
108
|
-
} else if ("hyloLpToken" in interfaceType) {
|
|
109
|
-
interfaceIndex = InterfaceType.HyloLpToken
|
|
110
|
-
} else if ("jupiterLend" in interfaceType) {
|
|
111
|
-
interfaceIndex = InterfaceType.JupiterLend
|
|
112
|
-
} else if ("kaminoVault" in interfaceType) {
|
|
113
|
-
interfaceIndex = InterfaceType.KaminoVault
|
|
114
|
-
} else if ("solstice" in interfaceType) {
|
|
115
|
-
interfaceIndex = InterfaceType.Solstice
|
|
116
|
-
} else if ("reflect" in interfaceType) {
|
|
117
|
-
interfaceIndex = InterfaceType.Reflect
|
|
118
|
-
} else if ("ore" in interfaceType) {
|
|
119
|
-
interfaceIndex = InterfaceType.Ore
|
|
120
|
-
} else if ("chainlink" in interfaceType) {
|
|
121
|
-
interfaceIndex = InterfaceType.Chainlink
|
|
122
|
-
} else if ("chainlinkDataStream" in interfaceType) {
|
|
123
|
-
interfaceIndex = InterfaceType.ChainlinkDataStream
|
|
124
|
-
} else if ("scope" in interfaceType) {
|
|
125
|
-
interfaceIndex = InterfaceType.Scope
|
|
126
|
-
} else if ("solsticeGlamVault" in interfaceType) {
|
|
127
|
-
interfaceIndex = InterfaceType.SolsticeGlamVault
|
|
128
|
-
} else {
|
|
129
|
-
throw new Error("Unsupported interface type")
|
|
130
|
-
}
|
|
97
|
+
const interfaceIndex = getInterfaceTypeIndex(interfaceType)
|
|
131
98
|
const pda = new GenericSyPda(genericStandardProgramId, interfaceIndex)
|
|
132
99
|
const fetcher = new ExponentFetcher({ connection: cnx, genericStandardProgramId })
|
|
133
100
|
const syMetaAddress = pda.syMeta({ yieldBearingMint })
|
|
@@ -157,6 +124,34 @@ export enum InterfaceType {
|
|
|
157
124
|
ChainlinkDataStream = 16,
|
|
158
125
|
Scope = 17,
|
|
159
126
|
SolsticeGlamVault = 18,
|
|
127
|
+
ExponentTranching = 19,
|
|
128
|
+
GlowVault = 20,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function getInterfaceTypeIndex(interfaceType: InterfaceTypeGeneric): InterfaceType {
|
|
132
|
+
if ("pyth" in interfaceType) return InterfaceType.Pyth
|
|
133
|
+
if ("splStakePool" in interfaceType) return InterfaceType.SplStakePool
|
|
134
|
+
if ("one" in interfaceType) return InterfaceType.One
|
|
135
|
+
if ("fragmetricSupportedAsset" in interfaceType) return InterfaceType.FragmetricSupportedAsset
|
|
136
|
+
if ("fragmetric" in interfaceType) return InterfaceType.Fragmetric
|
|
137
|
+
if ("meteora" in interfaceType) return InterfaceType.Meteora
|
|
138
|
+
if ("sanctum" in interfaceType) return InterfaceType.Sanctum
|
|
139
|
+
if ("jupiterPerps" in interfaceType) return InterfaceType.JupiterPerps
|
|
140
|
+
if ("adrena" in interfaceType) return InterfaceType.Adrena
|
|
141
|
+
if ("hyloLpToken" in interfaceType) return InterfaceType.HyloLpToken
|
|
142
|
+
if ("jupiterLend" in interfaceType) return InterfaceType.JupiterLend
|
|
143
|
+
if ("kaminoVault" in interfaceType) return InterfaceType.KaminoVault
|
|
144
|
+
if ("solstice" in interfaceType) return InterfaceType.Solstice
|
|
145
|
+
if ("reflect" in interfaceType) return InterfaceType.Reflect
|
|
146
|
+
if ("ore" in interfaceType) return InterfaceType.Ore
|
|
147
|
+
if ("chainlinkDataStream" in interfaceType) return InterfaceType.ChainlinkDataStream
|
|
148
|
+
if ("chainlink" in interfaceType) return InterfaceType.Chainlink
|
|
149
|
+
if ("scope" in interfaceType) return InterfaceType.Scope
|
|
150
|
+
if ("solsticeGlamVault" in interfaceType) return InterfaceType.SolsticeGlamVault
|
|
151
|
+
if ("exponentTranching" in interfaceType) return InterfaceType.ExponentTranching
|
|
152
|
+
if ("glowVault" in interfaceType) return InterfaceType.GlowVault
|
|
153
|
+
|
|
154
|
+
throw new Error("Unsupported interface type")
|
|
160
155
|
}
|
|
161
156
|
|
|
162
157
|
export function getInterfaceTypeObj(
|
|
@@ -219,6 +214,10 @@ export function getInterfaceTypeObj(
|
|
|
219
214
|
return { scope: { priceChain: scopePriceChain, maximumAgeSeconds: new BN(scopeMaximumAgeSeconds) } }
|
|
220
215
|
case InterfaceType.SolsticeGlamVault:
|
|
221
216
|
return { solsticeGlamVault: { padding: [] } }
|
|
217
|
+
case InterfaceType.ExponentTranching:
|
|
218
|
+
return { exponentTranching: {} }
|
|
219
|
+
case InterfaceType.GlowVault:
|
|
220
|
+
return { glowVault: { padding: [] } }
|
|
222
221
|
default:
|
|
223
222
|
throw new Error(`Unsupported interface type: ${interfaceType}`)
|
|
224
223
|
}
|
|
@@ -278,6 +277,10 @@ export function getInterfaceTypeFromString(interfaceType: string): InterfaceType
|
|
|
278
277
|
return { scope: { priceChain: [0, 512, 512, 512], maximumAgeSeconds: new BN(3600) } }
|
|
279
278
|
case "solstice-glam-vault":
|
|
280
279
|
return { solsticeGlamVault: { padding: [] } }
|
|
280
|
+
case "exponent-tranching":
|
|
281
|
+
return { exponentTranching: {} }
|
|
282
|
+
case "glow-vault":
|
|
283
|
+
return { glowVault: { padding: [] } }
|
|
281
284
|
default:
|
|
282
285
|
throw new Error(`Unsupported interface type: ${interfaceType}`)
|
|
283
286
|
}
|
|
@@ -306,50 +309,7 @@ export class GenericSySdk {
|
|
|
306
309
|
new AnchorProvider(new web3.Connection("https://api.devnet.solana.com"), new MyWallet(web3.Keypair.generate())),
|
|
307
310
|
)
|
|
308
311
|
|
|
309
|
-
|
|
310
|
-
let interfaceIndex: number
|
|
311
|
-
if ("pyth" in this.state.account.interfaceType) {
|
|
312
|
-
interfaceIndex = InterfaceType.Pyth
|
|
313
|
-
} else if ("splStakePool" in this.state.account.interfaceType) {
|
|
314
|
-
interfaceIndex = InterfaceType.SplStakePool
|
|
315
|
-
} else if ("one" in this.state.account.interfaceType) {
|
|
316
|
-
interfaceIndex = InterfaceType.One
|
|
317
|
-
} else if ("fragmetricSupportedAsset" in this.state.account.interfaceType) {
|
|
318
|
-
interfaceIndex = InterfaceType.FragmetricSupportedAsset
|
|
319
|
-
} else if ("fragmetric" in this.state.account.interfaceType) {
|
|
320
|
-
interfaceIndex = InterfaceType.Fragmetric
|
|
321
|
-
} else if ("meteora" in this.state.account.interfaceType) {
|
|
322
|
-
interfaceIndex = InterfaceType.Meteora
|
|
323
|
-
} else if ("sanctum" in this.state.account.interfaceType) {
|
|
324
|
-
interfaceIndex = InterfaceType.Sanctum
|
|
325
|
-
} else if ("jupiterPerps" in this.state.account.interfaceType) {
|
|
326
|
-
interfaceIndex = InterfaceType.JupiterPerps
|
|
327
|
-
} else if ("adrena" in this.state.account.interfaceType) {
|
|
328
|
-
interfaceIndex = InterfaceType.Adrena
|
|
329
|
-
} else if ("hyloLpToken" in this.state.account.interfaceType) {
|
|
330
|
-
interfaceIndex = InterfaceType.HyloLpToken
|
|
331
|
-
} else if ("jupiterLend" in this.state.account.interfaceType) {
|
|
332
|
-
interfaceIndex = InterfaceType.JupiterLend
|
|
333
|
-
} else if ("kaminoVault" in this.state.account.interfaceType) {
|
|
334
|
-
interfaceIndex = InterfaceType.KaminoVault
|
|
335
|
-
} else if ("solstice" in this.state.account.interfaceType) {
|
|
336
|
-
interfaceIndex = InterfaceType.Solstice
|
|
337
|
-
} else if ("reflect" in this.state.account.interfaceType) {
|
|
338
|
-
interfaceIndex = InterfaceType.Reflect
|
|
339
|
-
} else if ("ore" in this.state.account.interfaceType) {
|
|
340
|
-
interfaceIndex = InterfaceType.Ore
|
|
341
|
-
} else if ("chainlink" in this.state.account.interfaceType) {
|
|
342
|
-
interfaceIndex = InterfaceType.Chainlink
|
|
343
|
-
} else if ("chainlinkDataStream" in this.state.account.interfaceType) {
|
|
344
|
-
interfaceIndex = InterfaceType.ChainlinkDataStream
|
|
345
|
-
} else if ("scope" in this.state.account.interfaceType) {
|
|
346
|
-
interfaceIndex = InterfaceType.Scope
|
|
347
|
-
} else if ("solsticeGlamVault" in this.state.account.interfaceType) {
|
|
348
|
-
interfaceIndex = InterfaceType.SolsticeGlamVault
|
|
349
|
-
} else {
|
|
350
|
-
throw new Error("Unsupported interface type")
|
|
351
|
-
}
|
|
352
|
-
|
|
312
|
+
const interfaceIndex = getInterfaceTypeIndex(getGenericSyMetaInitInterfaceType(this.state.account))
|
|
353
313
|
this.syPda = new GenericSyPda(programId, interfaceIndex)
|
|
354
314
|
}
|
|
355
315
|
|
|
@@ -414,7 +374,7 @@ export class GenericSySdk {
|
|
|
414
374
|
} else if ("meteora" in interfaceType) {
|
|
415
375
|
const currentTs = Math.floor(Date.now() / 1000)
|
|
416
376
|
|
|
417
|
-
|
|
377
|
+
let accounts = {
|
|
418
378
|
pool: account.interfaceAccounts[0],
|
|
419
379
|
vaultA: account.interfaceAccounts[4],
|
|
420
380
|
vaultB: account.interfaceAccounts[5],
|
|
@@ -434,11 +394,10 @@ export class GenericSySdk {
|
|
|
434
394
|
|
|
435
395
|
return { syRate: exchangeRate }
|
|
436
396
|
} else if ("adrena" in interfaceType) {
|
|
437
|
-
|
|
438
|
-
const previousTotalFees = account.interfaceType.adrena.previousTotalFees
|
|
397
|
+
const previousTotalFees = interfaceType.adrena.previousTotalFees
|
|
439
398
|
const currentIndex = account.index
|
|
440
399
|
|
|
441
|
-
|
|
400
|
+
const accounts = {
|
|
442
401
|
pool: account.interfaceAccounts[0],
|
|
443
402
|
custody1: account.interfaceAccounts[1],
|
|
444
403
|
custody2: account.interfaceAccounts[2],
|
|
@@ -450,8 +409,7 @@ export class GenericSySdk {
|
|
|
450
409
|
|
|
451
410
|
return { syRate: syRate.index }
|
|
452
411
|
} else if ("jupiterPerps" in interfaceType) {
|
|
453
|
-
|
|
454
|
-
const j = account.interfaceType.jupiterPerps
|
|
412
|
+
const j = interfaceType.jupiterPerps
|
|
455
413
|
const { index } = await fetchJupiterPerpsIndex({
|
|
456
414
|
connection: cnx,
|
|
457
415
|
pool: account.interfaceAccounts[0],
|
|
@@ -574,6 +532,28 @@ export class GenericSySdk {
|
|
|
574
532
|
stslxMint,
|
|
575
533
|
})
|
|
576
534
|
return { syRate }
|
|
535
|
+
} else if ("exponentTranching" in interfaceType) {
|
|
536
|
+
const marketAddress = account.interfaceAccounts[0]
|
|
537
|
+
if (account.interfaceAccounts.length !== 1 || !marketAddress) {
|
|
538
|
+
throw new Error("Exponent Tranching interface requires exactly one market account")
|
|
539
|
+
}
|
|
540
|
+
const syRate = await fetchExponentTranchingRate({
|
|
541
|
+
connection: cnx,
|
|
542
|
+
marketAddress,
|
|
543
|
+
yieldBearingMint: account.yieldBearingMint,
|
|
544
|
+
})
|
|
545
|
+
return { syRate }
|
|
546
|
+
} else if ("glowVault" in interfaceType) {
|
|
547
|
+
const vaultAddress = account.interfaceAccounts[0]
|
|
548
|
+
if (account.interfaceAccounts.length !== 1 || !vaultAddress) {
|
|
549
|
+
throw new Error("Glow Vault interface requires exactly one vault account")
|
|
550
|
+
}
|
|
551
|
+
const syRate = await fetchGlowVaultRate({
|
|
552
|
+
connection: cnx,
|
|
553
|
+
vaultAddress,
|
|
554
|
+
expectedShareMint: account.yieldBearingMint,
|
|
555
|
+
})
|
|
556
|
+
return { syRate }
|
|
577
557
|
} else {
|
|
578
558
|
return { syRate: 1 }
|
|
579
559
|
}
|
|
@@ -596,53 +576,16 @@ export class GenericSySdk {
|
|
|
596
576
|
const account = await loadAccountState(cnx, yieldBearingMint, genericStandardProgramId, interfaceType)
|
|
597
577
|
const tokenProgramBase = (await cnx.getAccountInfo(yieldBearingMint))?.owner
|
|
598
578
|
|
|
599
|
-
|
|
600
|
-
if ("pyth" in interfaceType) {
|
|
601
|
-
interfaceIndex = InterfaceType.Pyth
|
|
602
|
-
} else if ("splStakePool" in interfaceType) {
|
|
603
|
-
interfaceIndex = InterfaceType.SplStakePool
|
|
604
|
-
} else if ("one" in interfaceType) {
|
|
605
|
-
interfaceIndex = InterfaceType.One
|
|
606
|
-
} else if ("fragmetricSupportedAsset" in interfaceType) {
|
|
607
|
-
interfaceIndex = InterfaceType.FragmetricSupportedAsset
|
|
608
|
-
} else if ("fragmetric" in interfaceType) {
|
|
609
|
-
interfaceIndex = InterfaceType.Fragmetric
|
|
610
|
-
} else if ("meteora" in interfaceType) {
|
|
611
|
-
interfaceIndex = InterfaceType.Meteora
|
|
612
|
-
} else if ("sanctum" in interfaceType) {
|
|
613
|
-
interfaceIndex = InterfaceType.Sanctum
|
|
614
|
-
} else if ("jupiterPerps" in interfaceType) {
|
|
615
|
-
interfaceIndex = InterfaceType.JupiterPerps
|
|
616
|
-
} else if ("adrena" in interfaceType) {
|
|
617
|
-
interfaceIndex = InterfaceType.Adrena
|
|
618
|
-
} else if ("hyloLpToken" in interfaceType) {
|
|
619
|
-
interfaceIndex = InterfaceType.HyloLpToken
|
|
620
|
-
} else if ("jupiterLend" in interfaceType) {
|
|
621
|
-
interfaceIndex = InterfaceType.JupiterLend
|
|
622
|
-
} else if ("kaminoVault" in interfaceType) {
|
|
623
|
-
interfaceIndex = InterfaceType.KaminoVault
|
|
624
|
-
} else if ("solstice" in interfaceType) {
|
|
625
|
-
interfaceIndex = InterfaceType.Solstice
|
|
626
|
-
} else if ("reflect" in interfaceType) {
|
|
627
|
-
interfaceIndex = InterfaceType.Reflect
|
|
628
|
-
} else if ("ore" in interfaceType) {
|
|
629
|
-
interfaceIndex = InterfaceType.Ore
|
|
630
|
-
} else if ("chainlink" in interfaceType) {
|
|
631
|
-
interfaceIndex = InterfaceType.Chainlink
|
|
632
|
-
} else if ("chainlinkDataStream" in interfaceType) {
|
|
633
|
-
interfaceIndex = InterfaceType.ChainlinkDataStream
|
|
634
|
-
} else if ("scope" in interfaceType) {
|
|
635
|
-
interfaceIndex = InterfaceType.Scope
|
|
636
|
-
} else if ("solsticeGlamVault" in interfaceType) {
|
|
637
|
-
interfaceIndex = InterfaceType.SolsticeGlamVault
|
|
638
|
-
} else {
|
|
639
|
-
throw new Error("Unsupported interface type")
|
|
640
|
-
}
|
|
579
|
+
const interfaceIndex = getInterfaceTypeIndex(getGenericSyMetaInitInterfaceType(account))
|
|
641
580
|
const selfAddress = new GenericSyPda(genericStandardProgramId, interfaceIndex).syMeta({
|
|
642
581
|
yieldBearingMint,
|
|
643
582
|
})
|
|
644
583
|
|
|
645
|
-
const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
|
|
584
|
+
const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
|
|
585
|
+
account,
|
|
586
|
+
getGenericSyMetaInterfaceType(account),
|
|
587
|
+
cnx,
|
|
588
|
+
)
|
|
646
589
|
|
|
647
590
|
const state: GenericSyState = {
|
|
648
591
|
selfAddress,
|
|
@@ -671,7 +614,11 @@ export class GenericSySdk {
|
|
|
671
614
|
const account = await fetcher.fetchGenericSyMeta(syMetaAddress)
|
|
672
615
|
const tokenProgramBase = (await cnx.getAccountInfo(account.yieldBearingMint))?.owner
|
|
673
616
|
|
|
674
|
-
const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
|
|
617
|
+
const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
|
|
618
|
+
account,
|
|
619
|
+
getGenericSyMetaInterfaceType(account),
|
|
620
|
+
cnx,
|
|
621
|
+
)
|
|
675
622
|
|
|
676
623
|
const state: GenericSyState = {
|
|
677
624
|
selfAddress: syMetaAddress,
|
|
@@ -686,14 +633,14 @@ export class GenericSySdk {
|
|
|
686
633
|
|
|
687
634
|
/** Reload the state of the account */
|
|
688
635
|
async reload(cnx: web3.Connection) {
|
|
689
|
-
const
|
|
636
|
+
const fetcher = new ExponentFetcher({ connection: cnx, genericStandardProgramId: this.program.programId })
|
|
637
|
+
const account = await fetcher.fetchGenericSyMeta(this.state.selfAddress)
|
|
638
|
+
this.state.account = account
|
|
639
|
+
const { syRate, additionalData } = await GenericSySdk.calculateSyRate(
|
|
640
|
+
account,
|
|
641
|
+
getGenericSyMetaInterfaceType(account),
|
|
690
642
|
cnx,
|
|
691
|
-
this.state.account.yieldBearingMint,
|
|
692
|
-
this.program.programId,
|
|
693
|
-
this.state.account.interfaceType,
|
|
694
643
|
)
|
|
695
|
-
this.state.account = account
|
|
696
|
-
const { syRate, additionalData } = await GenericSySdk.calculateSyRate(account, account.interfaceType, cnx)
|
|
697
644
|
this.state.syRate = syRate
|
|
698
645
|
this.state.additionalData = additionalData
|
|
699
646
|
}
|
|
@@ -702,6 +649,14 @@ export class GenericSySdk {
|
|
|
702
649
|
return this.state.account
|
|
703
650
|
}
|
|
704
651
|
|
|
652
|
+
get interfaceType() {
|
|
653
|
+
return getGenericSyMetaInterfaceType(this.account)
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
get initInterfaceType() {
|
|
657
|
+
return getGenericSyMetaInitInterfaceType(this.account)
|
|
658
|
+
}
|
|
659
|
+
|
|
705
660
|
get mintSy() {
|
|
706
661
|
return this.account.mintSy
|
|
707
662
|
}
|
|
@@ -751,10 +706,7 @@ export class GenericSySdk {
|
|
|
751
706
|
}
|
|
752
707
|
|
|
753
708
|
get fragmetricData() {
|
|
754
|
-
if (
|
|
755
|
-
!("fragmetric" in this.state.account.interfaceType) &&
|
|
756
|
-
!("fragmetricSupportedAsset" in this.state.account.interfaceType)
|
|
757
|
-
) {
|
|
709
|
+
if (!("fragmetric" in this.interfaceType) && !("fragmetricSupportedAsset" in this.interfaceType)) {
|
|
758
710
|
throw new Error("Not a fragmetric interface")
|
|
759
711
|
}
|
|
760
712
|
if (!this.state.additionalData?.fragmetricData) {
|
|
@@ -764,7 +716,7 @@ export class GenericSySdk {
|
|
|
764
716
|
}
|
|
765
717
|
|
|
766
718
|
get jupiterLendData() {
|
|
767
|
-
if (!("jupiterLend" in this.
|
|
719
|
+
if (!("jupiterLend" in this.interfaceType)) {
|
|
768
720
|
throw new Error("Not a Jupiter Lend interface")
|
|
769
721
|
}
|
|
770
722
|
if (!this.state.additionalData?.jupiterLendData) {
|
|
@@ -774,7 +726,7 @@ export class GenericSySdk {
|
|
|
774
726
|
}
|
|
775
727
|
|
|
776
728
|
get kaminoVaultData() {
|
|
777
|
-
if (!("kaminoVault" in this.
|
|
729
|
+
if (!("kaminoVault" in this.interfaceType)) {
|
|
778
730
|
throw new Error("Not a Kamino Vault interface")
|
|
779
731
|
}
|
|
780
732
|
if (!this.state.additionalData?.kaminoVaultData) {
|
|
@@ -804,11 +756,7 @@ export class GenericSySdk {
|
|
|
804
756
|
}))
|
|
805
757
|
.concat(this.emissions.map((e) => ({ pubkey: e.escrowAccount, isSigner: false, isWritable: false })))
|
|
806
758
|
|
|
807
|
-
if (
|
|
808
|
-
("fragmetric" in this.state.account.interfaceType ||
|
|
809
|
-
"fragmetricSupportedAsset" in this.state.account.interfaceType) &&
|
|
810
|
-
signer
|
|
811
|
-
) {
|
|
759
|
+
if (("fragmetric" in this.interfaceType || "fragmetricSupportedAsset" in this.interfaceType) && signer) {
|
|
812
760
|
// If skipWrap is true, return minimal accounts (skip additional interface-specific accounts)
|
|
813
761
|
if (this.config.skipWrap) {
|
|
814
762
|
return accounts
|
|
@@ -881,7 +829,7 @@ export class GenericSySdk {
|
|
|
881
829
|
)
|
|
882
830
|
}
|
|
883
831
|
|
|
884
|
-
if ("jupiterLend" in this.
|
|
832
|
+
if ("jupiterLend" in this.interfaceType) {
|
|
885
833
|
// If skipWrap is true, return minimal accounts (skip additional interface-specific accounts)
|
|
886
834
|
if (this.config.skipWrap) {
|
|
887
835
|
return accounts
|
|
@@ -1024,7 +972,7 @@ export class GenericSySdk {
|
|
|
1024
972
|
}
|
|
1025
973
|
}
|
|
1026
974
|
|
|
1027
|
-
if ("kaminoVault" in this.
|
|
975
|
+
if ("kaminoVault" in this.interfaceType) {
|
|
1028
976
|
// If skipWrap is true, return minimal accounts (skip additional interface-specific accounts)
|
|
1029
977
|
if (this.config.skipWrap) {
|
|
1030
978
|
return accounts
|
|
@@ -1155,9 +1103,33 @@ export class GenericSySdk {
|
|
|
1155
1103
|
.instruction()
|
|
1156
1104
|
}
|
|
1157
1105
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
if (
|
|
1106
|
+
private getFragmetricReceiptTokenAccountSetupInstruction(signer?: web3.PublicKey) {
|
|
1107
|
+
const isFragmetric = "fragmetric" in this.interfaceType || "fragmetricSupportedAsset" in this.interfaceType
|
|
1108
|
+
if (!signer || !isFragmetric || this.config.skipWrap) {
|
|
1109
|
+
return null
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
const { receiptTokenMint } = this.fragmetricData
|
|
1113
|
+
const userReceiptTokenAccount = getAssociatedTokenAddressSync(receiptTokenMint, signer, true, TOKEN_2022_PROGRAM_ID)
|
|
1114
|
+
|
|
1115
|
+
return createAssociatedTokenAccountIdempotentInstruction(
|
|
1116
|
+
signer,
|
|
1117
|
+
userReceiptTokenAccount,
|
|
1118
|
+
signer,
|
|
1119
|
+
receiptTokenMint,
|
|
1120
|
+
TOKEN_2022_PROGRAM_ID,
|
|
1121
|
+
)
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/** Returns interface-specific setup instructions for the signer. */
|
|
1125
|
+
preInstructions(signer?: web3.PublicKey) {
|
|
1126
|
+
const ixs: web3.TransactionInstruction[] = []
|
|
1127
|
+
const receiptTokenAccountSetupIx = this.getFragmetricReceiptTokenAccountSetupInstruction(signer)
|
|
1128
|
+
if (receiptTokenAccountSetupIx) {
|
|
1129
|
+
ixs.push(receiptTokenAccountSetupIx)
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if ("jupiterLend" in this.interfaceType) {
|
|
1161
1133
|
const jupiterLendData = this.state.additionalData?.jupiterLendData
|
|
1162
1134
|
if (!jupiterLendData) {
|
|
1163
1135
|
throw new Error("Jupiter lend data not loaded")
|
|
@@ -1197,7 +1169,7 @@ export class GenericSySdk {
|
|
|
1197
1169
|
ixs.push(refreshInstruction)
|
|
1198
1170
|
}
|
|
1199
1171
|
|
|
1200
|
-
if ("splStakePool" in this.
|
|
1172
|
+
if ("splStakePool" in this.interfaceType) {
|
|
1201
1173
|
const splStakePoolData = this.state.additionalData?.splStakePoolData
|
|
1202
1174
|
if (!splStakePoolData) {
|
|
1203
1175
|
throw new Error("SPL stake pool data not loaded")
|
|
@@ -1226,6 +1198,23 @@ export class GenericSySdk {
|
|
|
1226
1198
|
return ixs
|
|
1227
1199
|
}
|
|
1228
1200
|
|
|
1201
|
+
/** Returns signer setup and refresh instructions, including those that require live interface state. */
|
|
1202
|
+
async getPreInstructions(cnx: web3.Connection, signer?: web3.PublicKey): Promise<web3.TransactionInstruction[]> {
|
|
1203
|
+
const instructions = this.preInstructions(signer)
|
|
1204
|
+
if (!("exponentTranching" in this.interfaceType)) return instructions
|
|
1205
|
+
|
|
1206
|
+
const marketAddress = this.account.interfaceAccounts[0]
|
|
1207
|
+
if (this.account.interfaceAccounts.length !== 1 || !marketAddress) {
|
|
1208
|
+
throw new Error("Exponent Tranching interface requires exactly one market account")
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
const updateMarket = await buildExponentTranchingUpdateMarketInstruction({
|
|
1212
|
+
connection: cnx,
|
|
1213
|
+
marketAddress,
|
|
1214
|
+
})
|
|
1215
|
+
return [updateMarket, ...instructions]
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1229
1218
|
getSyState() {
|
|
1230
1219
|
return this.program.methods
|
|
1231
1220
|
.getState()
|
|
@@ -1304,6 +1293,37 @@ export class GenericSySdk {
|
|
|
1304
1293
|
})
|
|
1305
1294
|
.instruction()
|
|
1306
1295
|
}
|
|
1296
|
+
|
|
1297
|
+
ixChangeInterfaceType({
|
|
1298
|
+
signer,
|
|
1299
|
+
interfaceAccounts,
|
|
1300
|
+
interfaceType,
|
|
1301
|
+
}: {
|
|
1302
|
+
signer: web3.PublicKey
|
|
1303
|
+
interfaceAccounts: web3.PublicKey[]
|
|
1304
|
+
interfaceType: InterfaceTypeGeneric
|
|
1305
|
+
}) {
|
|
1306
|
+
return this.program.methods
|
|
1307
|
+
.changeInterfaceType(interfaceAccounts, interfaceType)
|
|
1308
|
+
.accountsStrict({
|
|
1309
|
+
adminState: this.adminState,
|
|
1310
|
+
feePayer: signer,
|
|
1311
|
+
meta: this.selfAddress,
|
|
1312
|
+
mintSy: this.mintSy,
|
|
1313
|
+
signer,
|
|
1314
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1315
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1316
|
+
yieldBearingMint: this.vrtMint,
|
|
1317
|
+
})
|
|
1318
|
+
.remainingAccounts(
|
|
1319
|
+
interfaceAccounts.map((pubkey) => ({
|
|
1320
|
+
pubkey,
|
|
1321
|
+
isSigner: false,
|
|
1322
|
+
isWritable: true,
|
|
1323
|
+
})),
|
|
1324
|
+
)
|
|
1325
|
+
.instruction()
|
|
1326
|
+
}
|
|
1307
1327
|
}
|
|
1308
1328
|
|
|
1309
1329
|
export function initSy(
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { BN, BorshAccountsCoder, type Idl, web3 } from "@coral-xyz/anchor"
|
|
2
|
+
|
|
3
|
+
import { IDL as EXPONENT_TRANCHING_IDL, PROGRAM_ID } from "@exponent-labs/exponent-tranching-idl"
|
|
4
|
+
|
|
5
|
+
const EXPONENT_TRANCHING_PROGRAM_ID = new web3.PublicKey(PROGRAM_ID)
|
|
6
|
+
const UPDATE_MARKET_DISCRIMINATOR = Buffer.from([153, 39, 2, 197, 179, 50, 199, 217])
|
|
7
|
+
const NUMBER_DENOMINATOR = 1_000_000_000_000n
|
|
8
|
+
|
|
9
|
+
type TranchingNumber = { 0: BN[] }
|
|
10
|
+
|
|
11
|
+
type CpiInterfaceContext = {
|
|
12
|
+
alt_index: number
|
|
13
|
+
is_signer: boolean
|
|
14
|
+
is_writable: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type ExponentTranchingMarketAccount = {
|
|
18
|
+
address_lookup_table: web3.PublicKey
|
|
19
|
+
sy_program: web3.PublicKey
|
|
20
|
+
mint_lp_senior: web3.PublicKey
|
|
21
|
+
mint_lp_junior: web3.PublicKey
|
|
22
|
+
return_model_storage: web3.PublicKey
|
|
23
|
+
financials: {
|
|
24
|
+
sr_effective_net_asset: TranchingNumber
|
|
25
|
+
jr_effective_net_asset: TranchingNumber
|
|
26
|
+
}
|
|
27
|
+
tranche_supply_state: {
|
|
28
|
+
total_senior_lp_supply: BN
|
|
29
|
+
total_junior_lp_supply: BN
|
|
30
|
+
}
|
|
31
|
+
sy_cpi_accounts: {
|
|
32
|
+
get_sy_state: CpiInterfaceContext[]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const accountCoder = new BorshAccountsCoder(EXPONENT_TRANCHING_IDL as Idl)
|
|
37
|
+
|
|
38
|
+
function tranchingNumberToRaw(value: TranchingNumber): bigint {
|
|
39
|
+
if (value[0].length !== 4) {
|
|
40
|
+
throw new Error("Invalid Exponent Tranching number")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let raw = 0n
|
|
44
|
+
for (let index = 3; index >= 0; index--) {
|
|
45
|
+
raw = (raw << 64n) + BigInt(value[0][index]!.toString())
|
|
46
|
+
}
|
|
47
|
+
return raw
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function calculateLpRate(effectiveNetAsset: TranchingNumber, totalLpSupply: BN): number {
|
|
51
|
+
const priceRaw =
|
|
52
|
+
(tranchingNumberToRaw(effectiveNetAsset) + NUMBER_DENOMINATOR) / (BigInt(totalLpSupply.toString()) + 1n)
|
|
53
|
+
return Number(priceRaw) / Number(NUMBER_DENOMINATOR)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function fetchMarket(
|
|
57
|
+
connection: web3.Connection,
|
|
58
|
+
marketAddress: web3.PublicKey,
|
|
59
|
+
): Promise<ExponentTranchingMarketAccount> {
|
|
60
|
+
const accountInfo = await connection.getAccountInfo(marketAddress)
|
|
61
|
+
if (!accountInfo) {
|
|
62
|
+
throw new Error(`Exponent Tranching market not found: ${marketAddress.toBase58()}`)
|
|
63
|
+
}
|
|
64
|
+
if (!accountInfo.owner.equals(EXPONENT_TRANCHING_PROGRAM_ID)) {
|
|
65
|
+
throw new Error(`Invalid Exponent Tranching market owner: ${accountInfo.owner.toBase58()}`)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return accountCoder.decode("ExponentTranchingMarket", accountInfo.data) as ExponentTranchingMarketAccount
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Reads the selected tranche's virtual-supply NAV from an Exponent Tranching market. */
|
|
72
|
+
export async function fetchExponentTranchingRate(params: {
|
|
73
|
+
connection: web3.Connection
|
|
74
|
+
marketAddress: web3.PublicKey
|
|
75
|
+
yieldBearingMint: web3.PublicKey
|
|
76
|
+
}): Promise<number> {
|
|
77
|
+
const market = await fetchMarket(params.connection, params.marketAddress)
|
|
78
|
+
|
|
79
|
+
if (params.yieldBearingMint.equals(market.mint_lp_senior)) {
|
|
80
|
+
return calculateLpRate(market.financials.sr_effective_net_asset, market.tranche_supply_state.total_senior_lp_supply)
|
|
81
|
+
}
|
|
82
|
+
if (params.yieldBearingMint.equals(market.mint_lp_junior)) {
|
|
83
|
+
return calculateLpRate(market.financials.jr_effective_net_asset, market.tranche_supply_state.total_junior_lp_supply)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw new Error(`Tranching market does not contain yield-bearing mint ${params.yieldBearingMint.toBase58()}`)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Builds the permissionless refresh required before reading a slot-fresh tranching NAV. */
|
|
90
|
+
export async function buildExponentTranchingUpdateMarketInstruction(params: {
|
|
91
|
+
connection: web3.Connection
|
|
92
|
+
marketAddress: web3.PublicKey
|
|
93
|
+
}): Promise<web3.TransactionInstruction> {
|
|
94
|
+
const market = await fetchMarket(params.connection, params.marketAddress)
|
|
95
|
+
const lookupTable = await params.connection.getAddressLookupTable(market.address_lookup_table)
|
|
96
|
+
if (!lookupTable.value) {
|
|
97
|
+
throw new Error(`Exponent Tranching lookup table not found: ${market.address_lookup_table.toBase58()}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const getSyStateAccounts = market.sy_cpi_accounts.get_sy_state.map((context) => {
|
|
101
|
+
const pubkey = lookupTable.value!.state.addresses[context.alt_index]
|
|
102
|
+
if (!pubkey) {
|
|
103
|
+
throw new Error(`Exponent Tranching get_sy_state ALT index ${context.alt_index} is out of bounds`)
|
|
104
|
+
}
|
|
105
|
+
return { pubkey, isSigner: context.is_signer, isWritable: context.is_writable }
|
|
106
|
+
})
|
|
107
|
+
const [eventAuthority] = web3.PublicKey.findProgramAddressSync(
|
|
108
|
+
[Buffer.from("__event_authority")],
|
|
109
|
+
EXPONENT_TRANCHING_PROGRAM_ID,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return new web3.TransactionInstruction({
|
|
113
|
+
programId: EXPONENT_TRANCHING_PROGRAM_ID,
|
|
114
|
+
data: UPDATE_MARKET_DISCRIMINATOR,
|
|
115
|
+
keys: [
|
|
116
|
+
{ pubkey: params.marketAddress, isSigner: false, isWritable: true },
|
|
117
|
+
{ pubkey: market.return_model_storage, isSigner: false, isWritable: true },
|
|
118
|
+
{ pubkey: market.address_lookup_table, isSigner: false, isWritable: false },
|
|
119
|
+
{ pubkey: market.sy_program, isSigner: false, isWritable: false },
|
|
120
|
+
{ pubkey: eventAuthority, isSigner: false, isWritable: false },
|
|
121
|
+
{ pubkey: EXPONENT_TRANCHING_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
122
|
+
...getSyStateAccounts,
|
|
123
|
+
],
|
|
124
|
+
})
|
|
125
|
+
}
|