@exponent-labs/exponent-sdk 0.0.3
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/CHANGELOG.md +16 -0
- package/build/addressLookupTableUtil.d.ts +12 -0
- package/build/addressLookupTableUtil.js +32 -0
- package/build/addressLookupTableUtil.js.map +1 -0
- package/build/environment.d.ts +10 -0
- package/build/environment.js +13 -0
- package/build/environment.js.map +1 -0
- package/build/events.d.ts +339 -0
- package/build/events.js +231 -0
- package/build/events.js.map +1 -0
- package/build/flavors.d.ts +24 -0
- package/build/flavors.js +713 -0
- package/build/flavors.js.map +1 -0
- package/build/index.d.ts +11 -0
- package/build/index.js +45 -0
- package/build/index.js.map +1 -0
- package/build/lpPosition.d.ts +35 -0
- package/build/lpPosition.js +103 -0
- package/build/lpPosition.js.map +1 -0
- package/build/market.d.ts +567 -0
- package/build/market.js +1445 -0
- package/build/market.js.map +1 -0
- package/build/syPosition.d.ts +6 -0
- package/build/syPosition.js +115 -0
- package/build/syPosition.js.map +1 -0
- package/build/tokenUtil.d.ts +3 -0
- package/build/tokenUtil.js +23 -0
- package/build/tokenUtil.js.map +1 -0
- package/build/utils/altUtil.d.ts +8 -0
- package/build/utils/altUtil.js +35 -0
- package/build/utils/altUtil.js.map +1 -0
- package/build/utils/binSolver.d.ts +1 -0
- package/build/utils/binSolver.js +45 -0
- package/build/utils/binSolver.js.map +1 -0
- package/build/utils/binSolver.test.d.ts +1 -0
- package/build/utils/binSolver.test.js +15 -0
- package/build/utils/binSolver.test.js.map +1 -0
- package/build/utils/index.d.ts +6 -0
- package/build/utils/index.js +31 -0
- package/build/utils/index.js.map +1 -0
- package/build/utils/ix.d.ts +6 -0
- package/build/utils/ix.js +3 -0
- package/build/utils/ix.js.map +1 -0
- package/build/vault.d.ts +289 -0
- package/build/vault.js +615 -0
- package/build/vault.js.map +1 -0
- package/build/ytPosition.d.ts +86 -0
- package/build/ytPosition.js +231 -0
- package/build/ytPosition.js.map +1 -0
- package/jest.config.js +5 -0
- package/package.json +42 -0
- package/src/addressLookupTableUtil.ts +34 -0
- package/src/environment.ts +19 -0
- package/src/events.ts +595 -0
- package/src/flavors.ts +773 -0
- package/src/index.ts +11 -0
- package/src/lpPosition.ts +129 -0
- package/src/market.ts +2338 -0
- package/src/syPosition.ts +151 -0
- package/src/tokenUtil.ts +20 -0
- package/src/utils/altUtil.ts +47 -0
- package/src/utils/binSolver.test.ts +15 -0
- package/src/utils/binSolver.ts +44 -0
- package/src/utils/index.ts +32 -0
- package/src/utils/ix.ts +7 -0
- package/src/vault.ts +999 -0
- package/src/ytPosition.ts +313 -0
- package/tsconfig.json +38 -0
package/src/market.ts
ADDED
|
@@ -0,0 +1,2338 @@
|
|
|
1
|
+
import { AnchorProvider, Program, Wallet, web3 } from "@coral-xyz/anchor"
|
|
2
|
+
import { ExponentFetcher, LiquidityNetBalanceLimits, LpFarm } from "@exponent-labs/exponent-fetcher"
|
|
3
|
+
import { ClaimAmount, ExponentIx } from "@exponent-labs/exponent-ix"
|
|
4
|
+
import {
|
|
5
|
+
createAssociatedTokenAccountIdempotentInstruction,
|
|
6
|
+
getAssociatedTokenAddressSync,
|
|
7
|
+
TOKEN_PROGRAM_ID,
|
|
8
|
+
} from "@solana/spl-token"
|
|
9
|
+
import { fetchAddressLookupTable, makeCpiAccountMetaLists } from "./addressLookupTableUtil"
|
|
10
|
+
import { Environment } from "./environment"
|
|
11
|
+
import { getMultipleMintSupply } from "./tokenUtil"
|
|
12
|
+
import {
|
|
13
|
+
makeFlavorMarginfiSync,
|
|
14
|
+
makeFlavorKaminoSync,
|
|
15
|
+
makeFlavorJitoRestakingSync,
|
|
16
|
+
makeFlavorPerenaSync,
|
|
17
|
+
makeFlavorGenericSync,
|
|
18
|
+
} from "./flavors"
|
|
19
|
+
import { ExponentCore, IDL } from "@exponent-labs/exponent-idl"
|
|
20
|
+
import { BN } from "@coral-xyz/anchor"
|
|
21
|
+
import { ExponentPDA } from "@exponent-labs/exponent-pda"
|
|
22
|
+
import { Vault } from "./vault"
|
|
23
|
+
import { LiquidityAdd, lpOutForTokensIn, MarketCalculator } from "@exponent-labs/market-math"
|
|
24
|
+
import { emitEventAuthority, getExponentAdminStatePda, uniqueRemainingAccounts } from "./utils"
|
|
25
|
+
import { CpiAccountsRaw, Flavor, SyPosition } from "@exponent-labs/exponent-types"
|
|
26
|
+
import { PreciseNumber } from "@exponent-labs/precise-number"
|
|
27
|
+
import { AnchorizedPNum } from "@exponent-labs/exponent-types"
|
|
28
|
+
import { extendAddressLookupTable } from "./utils/altUtil"
|
|
29
|
+
import { makeSyPosition } from "./syPosition"
|
|
30
|
+
import { serializeCpiAccountsRaw } from "@exponent-labs/exponent-ix"
|
|
31
|
+
import { CpiAccountsRawJson } from "@exponent-labs/exponent-types"
|
|
32
|
+
|
|
33
|
+
export { LiquidityAdd }
|
|
34
|
+
|
|
35
|
+
const SECONDS_PER_YEAR = 365 * 24 * 60 * 60
|
|
36
|
+
|
|
37
|
+
interface Emission {
|
|
38
|
+
/** Token account that holds emission tokens */
|
|
39
|
+
escrowAccountAddress: web3.PublicKey
|
|
40
|
+
|
|
41
|
+
/** Mint for the emission token */
|
|
42
|
+
mint: web3.PublicKey
|
|
43
|
+
|
|
44
|
+
/** Token program ID for the emission token */
|
|
45
|
+
tokenProgramAddress: web3.PublicKey
|
|
46
|
+
|
|
47
|
+
/** How many emissions have been claimed by SY holders */
|
|
48
|
+
totalClaimed: bigint
|
|
49
|
+
|
|
50
|
+
/** How many emissions have been earned by the SY robot over its lifetime */
|
|
51
|
+
lastSeenTotalAccruedEmissions: bigint
|
|
52
|
+
|
|
53
|
+
/** Global index for sharing out rewards to SY holders */
|
|
54
|
+
index: AnchorizedPNum
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type MarketAdminAction =
|
|
58
|
+
| { setStatus: [number] }
|
|
59
|
+
| { setMaxLpSupply: [BN] }
|
|
60
|
+
| { changeLnFeeRateRoot: [number] }
|
|
61
|
+
| { changeRateScalarRoot: [number] }
|
|
62
|
+
| {
|
|
63
|
+
changeLiquidityNetBalanceLimits: {
|
|
64
|
+
maxNetBalanceChangeNegativePercentage: number
|
|
65
|
+
maxNetBalanceChangePositivePercentage: number
|
|
66
|
+
windowDurationSeconds: number
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
| { removeMarketEmission: [number] }
|
|
70
|
+
|
|
71
|
+
type MarketArgs = {
|
|
72
|
+
ptBalance: bigint
|
|
73
|
+
syBalance: bigint
|
|
74
|
+
lpSupply: bigint
|
|
75
|
+
sySupply: bigint
|
|
76
|
+
lpEscrowAmount: bigint
|
|
77
|
+
maxLpSupply: bigint
|
|
78
|
+
rateScalarRoot: number
|
|
79
|
+
lnFeeRateRoot: number
|
|
80
|
+
lastLnImpliedRate: number
|
|
81
|
+
expirationTs: number
|
|
82
|
+
addressLookupTable: web3.PublicKey
|
|
83
|
+
mintSy: web3.PublicKey
|
|
84
|
+
mintPt: web3.PublicKey
|
|
85
|
+
vault: Vault
|
|
86
|
+
mintLp: web3.PublicKey
|
|
87
|
+
tokenPtEscrow: web3.PublicKey
|
|
88
|
+
tokenSyEscrow: web3.PublicKey
|
|
89
|
+
tokenLpEscrow: web3.PublicKey
|
|
90
|
+
syProgram: web3.PublicKey
|
|
91
|
+
statusFlags: number
|
|
92
|
+
cpiAccounts: CpiAccountsRaw
|
|
93
|
+
feeTreasurySyBps: number
|
|
94
|
+
tokenFeeTreasurySy: web3.PublicKey
|
|
95
|
+
isCurrentFlashSwap: boolean
|
|
96
|
+
lpFarm: LpFarm
|
|
97
|
+
flavor: Flavor
|
|
98
|
+
liquidityNetBalanceLimits: LiquidityNetBalanceLimits
|
|
99
|
+
syPosition: SyPosition
|
|
100
|
+
emissions: {
|
|
101
|
+
trackers: {
|
|
102
|
+
tokenEscrow: web3.PublicKey
|
|
103
|
+
lpShareIndex: number
|
|
104
|
+
lastSeenStaged: number
|
|
105
|
+
}[]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export class MyWallet implements Wallet {
|
|
110
|
+
constructor(readonly payer: web3.Keypair) {
|
|
111
|
+
this.payer = payer
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async signTransaction<T extends web3.Transaction | web3.VersionedTransaction>(tx: T): Promise<T> {
|
|
115
|
+
if (tx instanceof web3.Transaction) {
|
|
116
|
+
tx.partialSign(this.payer)
|
|
117
|
+
} else {
|
|
118
|
+
tx.sign([this.payer])
|
|
119
|
+
}
|
|
120
|
+
return tx
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async signAllTransactions<T extends web3.Transaction | web3.VersionedTransaction>(txs: T[]): Promise<T[]> {
|
|
124
|
+
return txs.map((t) => {
|
|
125
|
+
if (t instanceof web3.Transaction) {
|
|
126
|
+
t.partialSign(this.payer)
|
|
127
|
+
} else if (t instanceof web3.VersionedTransaction) {
|
|
128
|
+
t.sign([this.payer])
|
|
129
|
+
}
|
|
130
|
+
return t
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get publicKey(): web3.PublicKey {
|
|
135
|
+
return this.payer.publicKey
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export class Market {
|
|
140
|
+
coreProgram: Program<ExponentCore>
|
|
141
|
+
xponIx: ExponentIx
|
|
142
|
+
xponPda: ExponentPDA
|
|
143
|
+
|
|
144
|
+
constructor(
|
|
145
|
+
public state: MarketArgs,
|
|
146
|
+
public selfAddress: web3.PublicKey,
|
|
147
|
+
public env: Environment,
|
|
148
|
+
public connection: web3.Connection,
|
|
149
|
+
) {
|
|
150
|
+
this.xponPda = new ExponentPDA(env.coreProgramId)
|
|
151
|
+
this.xponIx = new ExponentIx(env.coreProgramId)
|
|
152
|
+
const mockWallet = new MyWallet(web3.Keypair.generate())
|
|
153
|
+
this.coreProgram = new Program(IDL as ExponentCore, new AnchorProvider(connection, mockWallet))
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static async load(
|
|
157
|
+
env: Environment,
|
|
158
|
+
connection: web3.Connection,
|
|
159
|
+
address: web3.PublicKey,
|
|
160
|
+
vault?: Vault,
|
|
161
|
+
): Promise<Market> {
|
|
162
|
+
const fetcher = new ExponentFetcher({ connection })
|
|
163
|
+
const m = await fetcher.fetchMarket(address)
|
|
164
|
+
const [[lpSupply, sySupply], alt, loadedVault] = await Promise.all([
|
|
165
|
+
getMultipleMintSupply(connection, [m.mintLp, m.mintSy]),
|
|
166
|
+
fetchAddressLookupTable(connection, m.addressLookupTable),
|
|
167
|
+
vault || Vault.load(env, connection, m.vault),
|
|
168
|
+
])
|
|
169
|
+
const cpiAccounts = makeCpiAccountMetaLists(alt, m.cpiAccounts)
|
|
170
|
+
|
|
171
|
+
const flavor = (() => {
|
|
172
|
+
switch (loadedVault.flavor.flavor) {
|
|
173
|
+
case "marginfi":
|
|
174
|
+
return makeFlavorMarginfiSync(loadedVault.flavor)
|
|
175
|
+
case "kamino":
|
|
176
|
+
return makeFlavorKaminoSync(loadedVault.flavor)
|
|
177
|
+
case "jitoRestaking":
|
|
178
|
+
return makeFlavorJitoRestakingSync(loadedVault.flavor)
|
|
179
|
+
case "perena":
|
|
180
|
+
return makeFlavorPerenaSync(loadedVault.flavor)
|
|
181
|
+
case "generic":
|
|
182
|
+
return makeFlavorGenericSync(loadedVault.flavor)
|
|
183
|
+
default:
|
|
184
|
+
throw new Error(`Unknown flavor: ${loadedVault.flavor}`)
|
|
185
|
+
}
|
|
186
|
+
})()
|
|
187
|
+
|
|
188
|
+
const syPosition = await makeSyPosition(fetcher, flavor, m.syProgram, address)
|
|
189
|
+
|
|
190
|
+
const state: MarketArgs = {
|
|
191
|
+
...m,
|
|
192
|
+
vault: loadedVault,
|
|
193
|
+
cpiAccounts,
|
|
194
|
+
lpSupply,
|
|
195
|
+
sySupply,
|
|
196
|
+
flavor,
|
|
197
|
+
syPosition,
|
|
198
|
+
}
|
|
199
|
+
return new Market(state, address, env, connection)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async reload(conn: web3.Connection = this.connection) {
|
|
203
|
+
const m = await Market.load(this.env, conn, this.selfAddress)
|
|
204
|
+
this.state = m.state
|
|
205
|
+
return m
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Convert to a JSON representation */
|
|
209
|
+
toJson() {
|
|
210
|
+
return toJson(this)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
get vault() {
|
|
214
|
+
return this.state.vault
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get flavor() {
|
|
218
|
+
return this.state.flavor
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
get lpSupply() {
|
|
222
|
+
return this.state.lpSupply
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
get syBalance() {
|
|
226
|
+
return this.state.syBalance
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
get ptBalance() {
|
|
230
|
+
return this.state.ptBalance
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
get mintSy() {
|
|
234
|
+
return this.state.mintSy
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
get mintPt() {
|
|
238
|
+
return this.state.mintPt
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
get statusFlags() {
|
|
242
|
+
return this.state.statusFlags
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
get mintYt() {
|
|
246
|
+
return this.vault.mintYt
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
get mintLp() {
|
|
250
|
+
return this.state.mintLp
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
get addressLookupTable() {
|
|
254
|
+
return this.state.addressLookupTable
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
get syProgram() {
|
|
258
|
+
return this.state.syProgram
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
get cpiAccounts() {
|
|
262
|
+
return this.state.cpiAccounts
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
get marketEmissions() {
|
|
266
|
+
return this.state.emissions
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
get emissions(): Emission[] {
|
|
270
|
+
if (this.flavor.flavor === "marginfi") {
|
|
271
|
+
return this.flavor.mfiSyState.account.emissions.map((e) => ({
|
|
272
|
+
escrowAccountAddress: e.escrowAccount,
|
|
273
|
+
mint: e.mint,
|
|
274
|
+
tokenProgramAddress: e.tokenProgram,
|
|
275
|
+
totalClaimed: BigInt(e.totalClaimedEmissions.toString()),
|
|
276
|
+
lastSeenTotalAccruedEmissions: BigInt(e.lastSeenTotalAccruedEmissions.toString()),
|
|
277
|
+
index: e.index,
|
|
278
|
+
}))
|
|
279
|
+
}
|
|
280
|
+
if (this.flavor.flavor === "kamino") {
|
|
281
|
+
return this.flavor.kaminoSyState.account.emissions.map((e) => ({
|
|
282
|
+
escrowAccountAddress: e.escrowAccount,
|
|
283
|
+
mint: e.mint,
|
|
284
|
+
tokenProgramAddress: e.tokenProgram,
|
|
285
|
+
totalClaimed: BigInt(e.totalClaimedEmissions.toString()),
|
|
286
|
+
lastSeenTotalAccruedEmissions: BigInt(e.lastSeenTotalAccruedEmissions.toString()),
|
|
287
|
+
index: e.index,
|
|
288
|
+
}))
|
|
289
|
+
}
|
|
290
|
+
if (this.flavor.flavor === "jitoRestaking") {
|
|
291
|
+
return this.flavor.jitoSyState.account.emissions.map((e) => ({
|
|
292
|
+
escrowAccountAddress: e.escrowAccount,
|
|
293
|
+
mint: e.mint,
|
|
294
|
+
tokenProgramAddress: e.tokenProgram,
|
|
295
|
+
totalClaimed: BigInt(e.totalClaimedEmissions.toString()),
|
|
296
|
+
lastSeenTotalAccruedEmissions: BigInt(e.lastSeenTotalAccruedEmissions.toString()),
|
|
297
|
+
index: e.index,
|
|
298
|
+
}))
|
|
299
|
+
}
|
|
300
|
+
if (this.flavor.flavor === "perena") {
|
|
301
|
+
return this.flavor.perenaSyState.account.emissions.map((e) => ({
|
|
302
|
+
escrowAccountAddress: e.escrowAccount,
|
|
303
|
+
mint: e.mint,
|
|
304
|
+
tokenProgramAddress: e.tokenProgram,
|
|
305
|
+
totalClaimed: BigInt(e.totalClaimedEmissions.toString()),
|
|
306
|
+
lastSeenTotalAccruedEmissions: BigInt(e.lastSeenTotalAccruedEmissions.toString()),
|
|
307
|
+
index: e.index,
|
|
308
|
+
}))
|
|
309
|
+
}
|
|
310
|
+
if (this.flavor.flavor === "generic") {
|
|
311
|
+
return this.flavor.genericSyState.account.emissions.map((e) => ({
|
|
312
|
+
escrowAccountAddress: e.escrowAccount,
|
|
313
|
+
mint: e.mint,
|
|
314
|
+
tokenProgramAddress: e.tokenProgram,
|
|
315
|
+
totalClaimed: BigInt(e.totalClaimedEmissions.toString()),
|
|
316
|
+
lastSeenTotalAccruedEmissions: BigInt(e.lastSeenTotalAccruedEmissions.toString()),
|
|
317
|
+
index: e.index,
|
|
318
|
+
}))
|
|
319
|
+
}
|
|
320
|
+
throw new Error("Unknown flavor")
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** Get the escrow token account addresses for the emissions, in order */
|
|
324
|
+
get emissionTokenAccounts(): web3.PublicKey[] {
|
|
325
|
+
return this.emissions.map((e) => e.escrowAccountAddress)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Pass-through SY account owned by the market */
|
|
329
|
+
get tokenSyEscrow(): web3.PublicKey {
|
|
330
|
+
return this.state.tokenSyEscrow
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** SY account that holds treasury SY fees from PT trading */
|
|
334
|
+
get tokenFeeTreasurySy(): web3.PublicKey {
|
|
335
|
+
return this.state.tokenFeeTreasurySy
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Market liquidity for PT */
|
|
339
|
+
get tokenPtEscrow(): web3.PublicKey {
|
|
340
|
+
return this.state.tokenPtEscrow
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
get tokenLpEscrow(): web3.PublicKey {
|
|
344
|
+
return this.state.tokenLpEscrow
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
get currentSyExchangeRate(): number {
|
|
348
|
+
return this.flavor.currentSyExchangeRate
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Special account for event emit self-cpi */
|
|
352
|
+
get eventAuthority(): web3.PublicKey {
|
|
353
|
+
return emitEventAuthority(this.env.coreProgramId)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
get currentPtPriceInSy(): number {
|
|
357
|
+
return this.currentPtPriceInAsset / this.currentSyExchangeRate
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
get currentPtPriceInAsset(): number {
|
|
361
|
+
const c = this.marketCalculator()
|
|
362
|
+
return c.exchangeRate
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
get ptDiscount(): number {
|
|
366
|
+
return 1 / this.currentPtPriceInAsset
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
get lpPriceInAsset(): number {
|
|
370
|
+
// Calculate total value of liquidity in asset units
|
|
371
|
+
const liquidityPoolTvl =
|
|
372
|
+
Number(this.syBalance) * this.flavor.currentSyExchangeRate + Number(this.ptBalance) / this.currentPtPriceInAsset
|
|
373
|
+
// Return LP price in asset units (0 if no supply to avoid division by zero)
|
|
374
|
+
return Number(this.lpSupply) === 0 ? 0 : liquidityPoolTvl / Number(this.lpSupply)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
get secondsRemaining(): number {
|
|
378
|
+
const now = Date.now() / 1000
|
|
379
|
+
return Math.max(0, Math.round(this.state.expirationTs - now))
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
get absolutePtYield(): number {
|
|
383
|
+
const ptAssetExchangeRate = this.ptDiscount
|
|
384
|
+
return (1 - ptAssetExchangeRate) / ptAssetExchangeRate
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Annualize a rate given the number of seconds remaining until maturity */
|
|
388
|
+
static annualize(r: number, secondsRemaining: number) {
|
|
389
|
+
return (r * SECONDS_PER_YEAR) / secondsRemaining
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** Annualized PT fixed rate */
|
|
393
|
+
get ptApr(): number {
|
|
394
|
+
return Market.annualize(this.absolutePtYield, this.secondsRemaining)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/** The fee rate taken off of trade fees (typically around 20%) expressed as a BPS number */
|
|
398
|
+
get feeTreasuryBps(): number {
|
|
399
|
+
return this.state.feeTreasurySyBps
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** The fee rate on assets when trading PT
|
|
403
|
+
* Expressed as a rational number
|
|
404
|
+
* eg 0.01 = 1%
|
|
405
|
+
*/
|
|
406
|
+
get feeRatePtTrade(): number {
|
|
407
|
+
return 1 - this.marketCalculator().feeRate
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** The fee rate taken off of trade fees (typically around 20%) expressed as a rational number */
|
|
411
|
+
get feeTreasuryRate(): number {
|
|
412
|
+
return this.feeTreasuryBps / 10_000
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Calculate amonut of LP tokens to expect for tokens in */
|
|
416
|
+
lpOutForTokensIn(syInIntent: bigint, ptInIntent: bigint): LiquidityAdd {
|
|
417
|
+
return lpOutForTokensIn({
|
|
418
|
+
syIntent: Number(syInIntent),
|
|
419
|
+
ptIntent: Number(ptInIntent),
|
|
420
|
+
lpSupply: Number(this.lpSupply),
|
|
421
|
+
syLiquidity: Number(this.syBalance),
|
|
422
|
+
ptLiquidity: Number(this.ptBalance),
|
|
423
|
+
})
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
marketCalculator() {
|
|
427
|
+
const secondsRemaining = Math.max(0, Math.round(this.state.expirationTs - Date.now() / 1000))
|
|
428
|
+
return new MarketCalculator({
|
|
429
|
+
liquiditySy: parseInt(this.syBalance.toString()),
|
|
430
|
+
liquidityPt: parseInt(this.ptBalance.toString()),
|
|
431
|
+
currentSyExchangeRate: this.currentSyExchangeRate,
|
|
432
|
+
lnFeeRateRoot: this.state.lnFeeRateRoot,
|
|
433
|
+
secondsRemaining,
|
|
434
|
+
lpTokenSupply: this.lpSupply,
|
|
435
|
+
rateScalarRoot: this.state.rateScalarRoot,
|
|
436
|
+
lastLnImpliedRate: this.state.lastLnImpliedRate,
|
|
437
|
+
maxNetBalanceChangeNegativePercentage: this.state.liquidityNetBalanceLimits.maxNetBalanceChangeNegativePercentage,
|
|
438
|
+
maxNetBalanceChangePositivePercentage: this.state.liquidityNetBalanceLimits.maxNetBalanceChangePositivePercentage,
|
|
439
|
+
windowStartTimestamp: this.state.liquidityNetBalanceLimits.windowStartTimestamp,
|
|
440
|
+
windowStartNetBalance: this.state.liquidityNetBalanceLimits.windowStartNetBalance.toNumber(),
|
|
441
|
+
windowDurationSeconds: this.state.liquidityNetBalanceLimits.windowDurationSeconds,
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** Deposit a pair of tokens as liquidity to the market
|
|
446
|
+
* Adds PT & SY from the `depositor` to the market
|
|
447
|
+
*
|
|
448
|
+
* Due to unforeseeable slippage, the PT & SY amounts intended are effectively the maximum amounts
|
|
449
|
+
* The minimum LP tokens to receive is specified by `minLpOut`
|
|
450
|
+
*
|
|
451
|
+
* The token accounts themselves are optional, and will be derived from the depositor's wallet if not provided
|
|
452
|
+
*/
|
|
453
|
+
async ixDepositLiquidity({
|
|
454
|
+
ptInIntent,
|
|
455
|
+
syInIntent,
|
|
456
|
+
minLpOut,
|
|
457
|
+
depositor,
|
|
458
|
+
ptSrc,
|
|
459
|
+
sySrc,
|
|
460
|
+
lpDst,
|
|
461
|
+
}: {
|
|
462
|
+
/** Intended (maximum) amount of PT in */
|
|
463
|
+
ptInIntent: bigint
|
|
464
|
+
/** Intended (maximum) amount of SY in */
|
|
465
|
+
syInIntent: bigint
|
|
466
|
+
/** Minimum LP tokens out */
|
|
467
|
+
minLpOut: bigint
|
|
468
|
+
depositor: web3.PublicKey
|
|
469
|
+
ptSrc?: web3.PublicKey
|
|
470
|
+
sySrc?: web3.PublicKey
|
|
471
|
+
lpDst?: web3.PublicKey
|
|
472
|
+
}) {
|
|
473
|
+
const tokenProgram = TOKEN_PROGRAM_ID
|
|
474
|
+
|
|
475
|
+
sySrc = sySrc || getAssociatedTokenAddressSync(this.mintSy, depositor, true, TOKEN_PROGRAM_ID)
|
|
476
|
+
ptSrc = ptSrc || getAssociatedTokenAddressSync(this.mintPt, depositor, true, TOKEN_PROGRAM_ID)
|
|
477
|
+
lpDst = lpDst || getAssociatedTokenAddressSync(this.mintLp, depositor, true, TOKEN_PROGRAM_ID)
|
|
478
|
+
|
|
479
|
+
const syRemAccounts = this.cpiAccounts.depositSy
|
|
480
|
+
|
|
481
|
+
return this.coreProgram.methods
|
|
482
|
+
.marketTwoDepositLiquidity(
|
|
483
|
+
new BN(ptInIntent.toString()),
|
|
484
|
+
new BN(syInIntent.toString()),
|
|
485
|
+
new BN(minLpOut.toString()),
|
|
486
|
+
)
|
|
487
|
+
.accountsStrict({
|
|
488
|
+
depositor,
|
|
489
|
+
market: this.selfAddress,
|
|
490
|
+
mintLp: this.mintLp,
|
|
491
|
+
tokenPtSrc: ptSrc,
|
|
492
|
+
tokenSySrc: sySrc,
|
|
493
|
+
tokenLpDst: lpDst,
|
|
494
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
495
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
496
|
+
addressLookupTable: this.addressLookupTable,
|
|
497
|
+
syProgram: this.syProgram,
|
|
498
|
+
tokenProgram,
|
|
499
|
+
eventAuthority: this.vault.eventAuthority,
|
|
500
|
+
program: this.coreProgram.programId,
|
|
501
|
+
})
|
|
502
|
+
.remainingAccounts(syRemAccounts)
|
|
503
|
+
.instruction()
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
async ixModifyMarketSetting({ signer, adminAction }: { signer: web3.PublicKey; adminAction: MarketAdminAction }) {
|
|
507
|
+
return this.coreProgram.methods
|
|
508
|
+
.modifyMarketSetting(adminAction)
|
|
509
|
+
.accountsStrict({
|
|
510
|
+
market: this.selfAddress,
|
|
511
|
+
adminState: getExponentAdminStatePda(),
|
|
512
|
+
signer,
|
|
513
|
+
systemProgram: web3.SystemProgram.programId,
|
|
514
|
+
})
|
|
515
|
+
.instruction()
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async ixModifyFarm({
|
|
519
|
+
newRate,
|
|
520
|
+
untilTimestamp,
|
|
521
|
+
signer,
|
|
522
|
+
farmMint,
|
|
523
|
+
farmTokenProgram,
|
|
524
|
+
farmTokenSrc,
|
|
525
|
+
}: {
|
|
526
|
+
newRate: bigint
|
|
527
|
+
untilTimestamp: number
|
|
528
|
+
signer: web3.PublicKey
|
|
529
|
+
farmMint: web3.PublicKey
|
|
530
|
+
farmTokenProgram: web3.PublicKey
|
|
531
|
+
farmTokenSrc?: web3.PublicKey
|
|
532
|
+
}) {
|
|
533
|
+
farmTokenSrc = farmTokenSrc || getAssociatedTokenAddressSync(farmMint, signer, true, farmTokenProgram)
|
|
534
|
+
|
|
535
|
+
const tokenFarm = getAssociatedTokenAddressSync(farmMint, this.selfAddress, true, farmTokenProgram)
|
|
536
|
+
|
|
537
|
+
return this.coreProgram.methods
|
|
538
|
+
.modifyFarm(untilTimestamp, new BN(newRate.toString()))
|
|
539
|
+
.accountsStrict({
|
|
540
|
+
adminState: getExponentAdminStatePda(),
|
|
541
|
+
market: this.selfAddress,
|
|
542
|
+
mint: farmMint,
|
|
543
|
+
tokenFarm: tokenFarm,
|
|
544
|
+
signer,
|
|
545
|
+
tokenProgram: farmTokenProgram,
|
|
546
|
+
tokenSource: farmTokenSrc,
|
|
547
|
+
})
|
|
548
|
+
.instruction()
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Redeem LP tokens for PT & SY (liquidity removal)
|
|
552
|
+
*
|
|
553
|
+
* The lpIn is exactly the amount of LP tokens to burn
|
|
554
|
+
* The minimum PT & SY out are specified by minPtOut & minSyOut
|
|
555
|
+
* The transaction may fail due to unforeseeable slippage on the redemption rate
|
|
556
|
+
*
|
|
557
|
+
* The token accounts themselves are optional, and will be derived from the withdrawer's wallet if not provided
|
|
558
|
+
*/
|
|
559
|
+
async ixWithdrawLiquidity({
|
|
560
|
+
lpIn,
|
|
561
|
+
withdrawer,
|
|
562
|
+
minPtOut,
|
|
563
|
+
minSyOut,
|
|
564
|
+
ptDst,
|
|
565
|
+
syDst,
|
|
566
|
+
lpSrc,
|
|
567
|
+
}: {
|
|
568
|
+
lpIn: bigint
|
|
569
|
+
withdrawer: web3.PublicKey
|
|
570
|
+
minPtOut: bigint
|
|
571
|
+
minSyOut: bigint
|
|
572
|
+
ptDst?: web3.PublicKey
|
|
573
|
+
syDst?: web3.PublicKey
|
|
574
|
+
lpSrc?: web3.PublicKey
|
|
575
|
+
}) {
|
|
576
|
+
ptDst = ptDst || getAssociatedTokenAddressSync(this.mintPt, withdrawer, true, TOKEN_PROGRAM_ID)
|
|
577
|
+
syDst = syDst || getAssociatedTokenAddressSync(this.mintSy, withdrawer, true, TOKEN_PROGRAM_ID)
|
|
578
|
+
lpSrc = lpSrc || getAssociatedTokenAddressSync(this.mintLp, withdrawer, true, TOKEN_PROGRAM_ID)
|
|
579
|
+
|
|
580
|
+
const ptDstAtaIx = createAssociatedTokenAccountIdempotentInstruction(withdrawer, ptDst, withdrawer, this.mintPt)
|
|
581
|
+
const syDstAtaIx = createAssociatedTokenAccountIdempotentInstruction(withdrawer, syDst, withdrawer, this.mintSy)
|
|
582
|
+
const lpSrcAtaIx = createAssociatedTokenAccountIdempotentInstruction(withdrawer, lpSrc, withdrawer, this.mintLp)
|
|
583
|
+
|
|
584
|
+
const syRemAccounts = this.cpiAccounts.withdrawSy
|
|
585
|
+
|
|
586
|
+
const ixs = await this.coreProgram.methods
|
|
587
|
+
.marketTwoWithdrawLiquidity(new BN(lpIn.toString()), new BN(minPtOut.toString()), new BN(minSyOut.toString()))
|
|
588
|
+
.accountsStrict({
|
|
589
|
+
withdrawer,
|
|
590
|
+
market: this.selfAddress,
|
|
591
|
+
mintLp: this.mintLp,
|
|
592
|
+
tokenPtDst: ptDst,
|
|
593
|
+
tokenSyDst: syDst,
|
|
594
|
+
tokenLpSrc: lpSrc,
|
|
595
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
596
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
597
|
+
addressLookupTable: this.addressLookupTable,
|
|
598
|
+
syProgram: this.syProgram,
|
|
599
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
600
|
+
eventAuthority: this.vault.eventAuthority,
|
|
601
|
+
program: this.coreProgram.programId,
|
|
602
|
+
})
|
|
603
|
+
.remainingAccounts(syRemAccounts)
|
|
604
|
+
.instruction()
|
|
605
|
+
|
|
606
|
+
return { ixs: [ixs], setupIxs: [ptDstAtaIx, syDstAtaIx, lpSrcAtaIx] }
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/** Buy PT with SY
|
|
610
|
+
*
|
|
611
|
+
* The trader is the account that sends the SY
|
|
612
|
+
* The amountPt is the exact amount of PT the trader intends to buy
|
|
613
|
+
* The syConstraint is the maximum amount of SY the trader is willing to spend
|
|
614
|
+
*
|
|
615
|
+
* The token accounts themselves are optional, and will be derived from the trader's wallet if not provided
|
|
616
|
+
*/
|
|
617
|
+
async ixBuyPt({
|
|
618
|
+
trader,
|
|
619
|
+
amountPt,
|
|
620
|
+
maxSySpend,
|
|
621
|
+
tokenPt,
|
|
622
|
+
tokenSy,
|
|
623
|
+
}: {
|
|
624
|
+
trader: web3.PublicKey
|
|
625
|
+
amountPt: bigint
|
|
626
|
+
maxSySpend: bigint
|
|
627
|
+
tokenPt?: web3.PublicKey
|
|
628
|
+
tokenSy?: web3.PublicKey
|
|
629
|
+
}) {
|
|
630
|
+
return this.ixTradePt({
|
|
631
|
+
trader,
|
|
632
|
+
traderPt: amountPt,
|
|
633
|
+
syConstraint: maxSySpend,
|
|
634
|
+
isBuy: true,
|
|
635
|
+
tokenPt,
|
|
636
|
+
tokenSy,
|
|
637
|
+
})
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Sell PT for SY
|
|
642
|
+
* The trader is the account that sends the PT
|
|
643
|
+
* The amountPt is the exact amount of PT the trader intends to sell
|
|
644
|
+
* The minSyReceive is the minimum amount of SY the trader is willing to receive
|
|
645
|
+
*
|
|
646
|
+
* The token accounts themselves are optional, and will be derived from the trader's wallet if not provided
|
|
647
|
+
*/
|
|
648
|
+
async ixSellPt({
|
|
649
|
+
trader,
|
|
650
|
+
amountPt,
|
|
651
|
+
minSyReceive,
|
|
652
|
+
tokenPt,
|
|
653
|
+
tokenSy,
|
|
654
|
+
}: {
|
|
655
|
+
trader: web3.PublicKey
|
|
656
|
+
amountPt: bigint
|
|
657
|
+
minSyReceive: bigint
|
|
658
|
+
tokenPt?: web3.PublicKey
|
|
659
|
+
tokenSy?: web3.PublicKey
|
|
660
|
+
}) {
|
|
661
|
+
return this.ixTradePt({
|
|
662
|
+
trader,
|
|
663
|
+
traderPt: amountPt,
|
|
664
|
+
syConstraint: minSyReceive,
|
|
665
|
+
isBuy: false,
|
|
666
|
+
tokenPt,
|
|
667
|
+
tokenSy,
|
|
668
|
+
})
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
async ixTradePt({
|
|
672
|
+
trader,
|
|
673
|
+
traderPt,
|
|
674
|
+
syConstraint,
|
|
675
|
+
isBuy,
|
|
676
|
+
tokenPt,
|
|
677
|
+
tokenSy,
|
|
678
|
+
}: {
|
|
679
|
+
trader: web3.PublicKey
|
|
680
|
+
traderPt: bigint
|
|
681
|
+
syConstraint: bigint
|
|
682
|
+
isBuy: boolean
|
|
683
|
+
tokenPt?: web3.PublicKey
|
|
684
|
+
tokenSy?: web3.PublicKey
|
|
685
|
+
}) {
|
|
686
|
+
tokenPt = tokenPt || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
|
|
687
|
+
tokenSy = tokenSy || getAssociatedTokenAddressSync(this.mintSy, trader, true, TOKEN_PROGRAM_ID)
|
|
688
|
+
|
|
689
|
+
const tokenSyAtaIx = createAssociatedTokenAccountIdempotentInstruction(trader, tokenSy, trader, this.mintSy)
|
|
690
|
+
const tokenPtAtaIx = createAssociatedTokenAccountIdempotentInstruction(trader, tokenPt, trader, this.mintPt)
|
|
691
|
+
|
|
692
|
+
const remainingAccounts = [
|
|
693
|
+
...this.cpiAccounts.getSyState,
|
|
694
|
+
...this.cpiAccounts.depositSy,
|
|
695
|
+
...this.cpiAccounts.withdrawSy,
|
|
696
|
+
]
|
|
697
|
+
|
|
698
|
+
const netTradePtBN = new BN(traderPt.toString()).mul(isBuy ? new BN(1) : new BN(-1))
|
|
699
|
+
const syConstraintBN = new BN(syConstraint.toString()).mul(isBuy ? new BN(-1) : new BN(1))
|
|
700
|
+
|
|
701
|
+
const ix = await this.coreProgram.methods
|
|
702
|
+
.tradePt(netTradePtBN, syConstraintBN)
|
|
703
|
+
.accountsStrict({
|
|
704
|
+
trader,
|
|
705
|
+
market: this.selfAddress,
|
|
706
|
+
tokenPtTrader: tokenPt,
|
|
707
|
+
tokenSyTrader: tokenSy,
|
|
708
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
709
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
710
|
+
addressLookupTable: this.addressLookupTable,
|
|
711
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
712
|
+
syProgram: this.syProgram,
|
|
713
|
+
tokenFeeTreasurySy: this.vault.state.treasurySyTokenAccount,
|
|
714
|
+
eventAuthority: this.vault.eventAuthority,
|
|
715
|
+
program: this.coreProgram.programId,
|
|
716
|
+
})
|
|
717
|
+
.remainingAccounts(remainingAccounts)
|
|
718
|
+
.instruction()
|
|
719
|
+
|
|
720
|
+
return { ixs: [ix], setupIxs: [tokenPtAtaIx, tokenSyAtaIx] }
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/** Sell YT for SY
|
|
724
|
+
*
|
|
725
|
+
* The trader is the account that sends the YT
|
|
726
|
+
*
|
|
727
|
+
* The amountYt is the exact amount of YT the trader intends to sell
|
|
728
|
+
*
|
|
729
|
+
* The minSyOut is the minimum amount of SY the trader is willing to receive
|
|
730
|
+
*
|
|
731
|
+
* The token accounts themselves are optional, and will be derived from the trader's wallet if not provided
|
|
732
|
+
*/
|
|
733
|
+
async ixSellYt({
|
|
734
|
+
trader,
|
|
735
|
+
ytIn,
|
|
736
|
+
minSyOut,
|
|
737
|
+
ytSrc,
|
|
738
|
+
ptSrc,
|
|
739
|
+
syDst,
|
|
740
|
+
}: {
|
|
741
|
+
trader: web3.PublicKey
|
|
742
|
+
ytIn: bigint
|
|
743
|
+
minSyOut: bigint
|
|
744
|
+
ytSrc?: web3.PublicKey
|
|
745
|
+
ptSrc?: web3.PublicKey
|
|
746
|
+
syDst?: web3.PublicKey
|
|
747
|
+
}) {
|
|
748
|
+
syDst = syDst || getAssociatedTokenAddressSync(this.mintSy, trader, true, TOKEN_PROGRAM_ID)
|
|
749
|
+
ptSrc = ptSrc || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
|
|
750
|
+
ytSrc = ytSrc || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
|
|
751
|
+
|
|
752
|
+
const syDstAtaIxs = createAssociatedTokenAccountIdempotentInstruction(trader, syDst, trader, this.mintSy)
|
|
753
|
+
const ptSrcAtaIxs = createAssociatedTokenAccountIdempotentInstruction(trader, ptSrc, trader, this.mintPt)
|
|
754
|
+
const ytSrcAtaIxs = createAssociatedTokenAccountIdempotentInstruction(trader, ytSrc, trader, this.mintYt)
|
|
755
|
+
|
|
756
|
+
const mergeAccounts = this.vault.mergeAccounts({ owner: trader, ytSrc, ptSrc, syDst })
|
|
757
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
758
|
+
...this.cpiAccounts.getSyState,
|
|
759
|
+
...this.cpiAccounts.depositSy,
|
|
760
|
+
...mergeAccounts.remainingAccounts,
|
|
761
|
+
])
|
|
762
|
+
remainingAccounts.push({ pubkey: this.coreProgram.programId, isWritable: false, isSigner: false })
|
|
763
|
+
|
|
764
|
+
const ix = await this.coreProgram.methods
|
|
765
|
+
.sellYt(new BN(ytIn.toString()), new BN(minSyOut.toString()))
|
|
766
|
+
.accountsStrict({
|
|
767
|
+
trader,
|
|
768
|
+
market: this.selfAddress,
|
|
769
|
+
tokenYtTrader: ytSrc,
|
|
770
|
+
tokenPtTrader: ptSrc,
|
|
771
|
+
tokenSyTrader: syDst,
|
|
772
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
773
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
774
|
+
addressLookupTable: this.addressLookupTable,
|
|
775
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
776
|
+
vault: mergeAccounts.mainAccounts.vault,
|
|
777
|
+
authorityVault: mergeAccounts.mainAccounts.authority,
|
|
778
|
+
tokenSyEscrowVault: mergeAccounts.mainAccounts.escrowSy,
|
|
779
|
+
mintYt: this.mintYt,
|
|
780
|
+
mintPt: this.mintPt,
|
|
781
|
+
addressLookupTableVault: mergeAccounts.mainAccounts.addressLookupTable,
|
|
782
|
+
yieldPositionVault: mergeAccounts.mainAccounts.yieldPosition,
|
|
783
|
+
syProgram: this.syProgram,
|
|
784
|
+
tokenFeeTreasurySy: this.vault.state.treasurySyTokenAccount,
|
|
785
|
+
eventAuthority: this.vault.eventAuthority,
|
|
786
|
+
program: this.coreProgram.programId,
|
|
787
|
+
})
|
|
788
|
+
.remainingAccounts(remainingAccounts)
|
|
789
|
+
.instruction()
|
|
790
|
+
|
|
791
|
+
return { ixs: [ix], setupIxs: [syDstAtaIxs, ptSrcAtaIxs, ytSrcAtaIxs] }
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/** Buy YT with SY
|
|
795
|
+
*
|
|
796
|
+
* The trader is the account that sends the SY
|
|
797
|
+
*
|
|
798
|
+
* The ytOut is the exact amount of YT the trader intends to buy
|
|
799
|
+
*
|
|
800
|
+
* The maxSyIn is the maximum amount of SY the trader is willing to spend
|
|
801
|
+
*
|
|
802
|
+
* The token accounts themselves are optional, and will be derived from the trader's wallet if not provided
|
|
803
|
+
*/
|
|
804
|
+
async ixBuyYt({
|
|
805
|
+
trader,
|
|
806
|
+
ytOut,
|
|
807
|
+
maxSyIn,
|
|
808
|
+
ytTrader,
|
|
809
|
+
ptTrader,
|
|
810
|
+
syTrader,
|
|
811
|
+
}: {
|
|
812
|
+
trader: web3.PublicKey
|
|
813
|
+
ytOut: bigint
|
|
814
|
+
maxSyIn: bigint
|
|
815
|
+
ytTrader?: web3.PublicKey
|
|
816
|
+
ptTrader?: web3.PublicKey
|
|
817
|
+
syTrader?: web3.PublicKey
|
|
818
|
+
}) {
|
|
819
|
+
syTrader = syTrader || getAssociatedTokenAddressSync(this.mintSy, trader, true, TOKEN_PROGRAM_ID)
|
|
820
|
+
ptTrader = ptTrader || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
|
|
821
|
+
ytTrader = ytTrader || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
|
|
822
|
+
|
|
823
|
+
const syTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(trader, syTrader, trader, this.mintSy)
|
|
824
|
+
const ptTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(trader, ptTrader, trader, this.mintPt)
|
|
825
|
+
const ytTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(trader, ytTrader, trader, this.mintYt)
|
|
826
|
+
|
|
827
|
+
const stripAccounts = this.vault.stripAccounts({
|
|
828
|
+
depositor: trader,
|
|
829
|
+
ytDst: ytTrader,
|
|
830
|
+
ptDst: ptTrader,
|
|
831
|
+
sySrc: syTrader,
|
|
832
|
+
})
|
|
833
|
+
|
|
834
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
835
|
+
...this.cpiAccounts.getSyState,
|
|
836
|
+
...this.cpiAccounts.withdrawSy,
|
|
837
|
+
...this.cpiAccounts.depositSy,
|
|
838
|
+
...stripAccounts.remainingAccounts,
|
|
839
|
+
])
|
|
840
|
+
remainingAccounts.push({ pubkey: this.coreProgram.programId, isWritable: false, isSigner: false })
|
|
841
|
+
|
|
842
|
+
const ix = await this.coreProgram.methods
|
|
843
|
+
.buyYt(new BN(maxSyIn.toString()), new BN(ytOut.toString()))
|
|
844
|
+
.accountsStrict({
|
|
845
|
+
trader,
|
|
846
|
+
market: this.selfAddress,
|
|
847
|
+
tokenYtTrader: ytTrader,
|
|
848
|
+
tokenPtTrader: ptTrader,
|
|
849
|
+
tokenSyTrader: syTrader,
|
|
850
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
851
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
852
|
+
addressLookupTable: this.addressLookupTable,
|
|
853
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
854
|
+
syProgram: this.syProgram,
|
|
855
|
+
vault: stripAccounts.mainAccounts.vault,
|
|
856
|
+
vaultAuthority: stripAccounts.mainAccounts.authority,
|
|
857
|
+
tokenSyEscrowVault: stripAccounts.mainAccounts.escrowSy,
|
|
858
|
+
mintYt: this.mintYt,
|
|
859
|
+
mintPt: this.mintPt,
|
|
860
|
+
addressLookupTableVault: stripAccounts.mainAccounts.addressLookupTable,
|
|
861
|
+
yieldPosition: stripAccounts.mainAccounts.yieldPosition,
|
|
862
|
+
tokenFeeTreasurySy: this.vault.state.treasurySyTokenAccount,
|
|
863
|
+
eventAuthority: this.vault.eventAuthority,
|
|
864
|
+
program: this.coreProgram.programId,
|
|
865
|
+
})
|
|
866
|
+
.remainingAccounts(remainingAccounts)
|
|
867
|
+
.instruction()
|
|
868
|
+
|
|
869
|
+
return { ixs: [ix], setupIxs: [syTraderAtaIx, ptTraderAtaIx, ytTraderAtaIx] }
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
async ixInitLpPosition({ owner, feePayer }: { owner: web3.PublicKey; feePayer?: web3.PublicKey }) {
|
|
873
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner })
|
|
874
|
+
return this.coreProgram.methods
|
|
875
|
+
.initLpPosition()
|
|
876
|
+
.accountsStrict({
|
|
877
|
+
owner,
|
|
878
|
+
feePayer: feePayer || owner,
|
|
879
|
+
lpPosition,
|
|
880
|
+
market: this.selfAddress,
|
|
881
|
+
systemProgram: web3.SystemProgram.programId,
|
|
882
|
+
eventAuthority: this.vault.eventAuthority,
|
|
883
|
+
program: this.coreProgram.programId,
|
|
884
|
+
})
|
|
885
|
+
.instruction()
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/** Deposit LP tokens into the farming module to earn rewards */
|
|
889
|
+
async ixDepositLp({ owner, amount, lpSrc }: { owner: web3.PublicKey; amount: bigint; lpSrc?: web3.PublicKey }) {
|
|
890
|
+
lpSrc = lpSrc || getAssociatedTokenAddressSync(this.mintLp, owner, true, TOKEN_PROGRAM_ID)
|
|
891
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner })
|
|
892
|
+
|
|
893
|
+
return this.coreProgram.methods
|
|
894
|
+
.marketDepositLp(new BN(amount.toString()))
|
|
895
|
+
.accountsStrict({
|
|
896
|
+
owner,
|
|
897
|
+
lpPosition,
|
|
898
|
+
tokenLpSrc: lpSrc,
|
|
899
|
+
tokenLpEscrow: this.tokenLpEscrow,
|
|
900
|
+
market: this.selfAddress,
|
|
901
|
+
addressLookupTable: this.addressLookupTable,
|
|
902
|
+
syProgram: this.syProgram,
|
|
903
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
904
|
+
mintLp: this.mintLp,
|
|
905
|
+
systemProgram: web3.SystemProgram.programId,
|
|
906
|
+
eventAuthority: this.vault.eventAuthority,
|
|
907
|
+
program: this.coreProgram.programId,
|
|
908
|
+
})
|
|
909
|
+
.remainingAccounts(this.cpiAccounts.getPositionState)
|
|
910
|
+
.instruction()
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/** Withdraw LP tokens from the farming module */
|
|
914
|
+
async ixWithdrawLp({ owner, amount, lpDst }: { owner: web3.PublicKey; amount: bigint; lpDst?: web3.PublicKey }) {
|
|
915
|
+
lpDst = lpDst || getAssociatedTokenAddressSync(this.mintLp, owner, true, TOKEN_PROGRAM_ID)
|
|
916
|
+
|
|
917
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner })
|
|
918
|
+
return this.coreProgram.methods
|
|
919
|
+
.marketWithdrawLp(new BN(amount.toString()))
|
|
920
|
+
.accountsStrict({
|
|
921
|
+
owner,
|
|
922
|
+
lpPosition,
|
|
923
|
+
tokenLpDst: lpDst,
|
|
924
|
+
tokenLpEscrow: this.tokenLpEscrow,
|
|
925
|
+
market: this.selfAddress,
|
|
926
|
+
addressLookupTable: this.addressLookupTable,
|
|
927
|
+
mintLp: this.mintLp,
|
|
928
|
+
syProgram: this.syProgram,
|
|
929
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
930
|
+
systemProgram: web3.SystemProgram.programId,
|
|
931
|
+
eventAuthority: this.vault.eventAuthority,
|
|
932
|
+
program: this.coreProgram.programId,
|
|
933
|
+
})
|
|
934
|
+
.remainingAccounts(this.cpiAccounts.getPositionState)
|
|
935
|
+
.instruction()
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
async ixWrapperCollectInterest({ claimer, tokenSyDst }: { claimer: web3.PublicKey; tokenSyDst?: web3.PublicKey }) {
|
|
939
|
+
const yieldPosition = this.xponPda.yieldPosition({ owner: claimer, vault: this.vault.selfAddress })
|
|
940
|
+
tokenSyDst = tokenSyDst || getAssociatedTokenAddressSync(this.mintSy, claimer, true, TOKEN_PROGRAM_ID)
|
|
941
|
+
const tokenBaseClaimer = getAssociatedTokenAddressSync(
|
|
942
|
+
this.flavor.mintBase,
|
|
943
|
+
claimer,
|
|
944
|
+
true,
|
|
945
|
+
this.flavor.baseTokenProgram,
|
|
946
|
+
)
|
|
947
|
+
const tokenBaseClaimerAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
948
|
+
claimer,
|
|
949
|
+
tokenBaseClaimer,
|
|
950
|
+
claimer,
|
|
951
|
+
this.flavor.mintBase,
|
|
952
|
+
)
|
|
953
|
+
|
|
954
|
+
const tokenSyClaimer = getAssociatedTokenAddressSync(this.mintSy, claimer, true)
|
|
955
|
+
const tokenSyClaimerAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
956
|
+
claimer,
|
|
957
|
+
tokenSyClaimer,
|
|
958
|
+
claimer,
|
|
959
|
+
this.mintSy,
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
963
|
+
...this.vault.cpiAccounts.getSyState,
|
|
964
|
+
...this.vault.cpiAccounts.withdrawSy,
|
|
965
|
+
])
|
|
966
|
+
|
|
967
|
+
const redeemSyIx = await this.flavor.ixRedeemSy({
|
|
968
|
+
amountSy: "0",
|
|
969
|
+
redeemer: claimer,
|
|
970
|
+
redeemerBaseTokenAccount: tokenBaseClaimer,
|
|
971
|
+
redeemerSyTokenAccount: tokenSyDst,
|
|
972
|
+
})
|
|
973
|
+
|
|
974
|
+
const ix = await this.coreProgram.methods
|
|
975
|
+
.wrapperCollectInterest(redeemSyIx.keys.length)
|
|
976
|
+
.accountsStrict({
|
|
977
|
+
addressLookupTable: this.vault.addressLookupTable,
|
|
978
|
+
authority: this.vault.state.authority,
|
|
979
|
+
claimer,
|
|
980
|
+
escrowSy: this.vault.escrowSy,
|
|
981
|
+
syProgram: this.syProgram,
|
|
982
|
+
vault: this.vault.selfAddress,
|
|
983
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
984
|
+
treasurySyTokenAccount: this.vault.state.treasurySyTokenAccount,
|
|
985
|
+
yieldPosition: yieldPosition,
|
|
986
|
+
tokenSyDst,
|
|
987
|
+
eventAuthority: this.vault.eventAuthority,
|
|
988
|
+
program: this.coreProgram.programId,
|
|
989
|
+
})
|
|
990
|
+
.remainingAccounts(redeemSyIx.keys.concat(remainingAccounts))
|
|
991
|
+
.instruction()
|
|
992
|
+
|
|
993
|
+
return {
|
|
994
|
+
ixs: [
|
|
995
|
+
...(await this.flavor.preIxs({ signer: claimer })),
|
|
996
|
+
ix,
|
|
997
|
+
...(await this.flavor.postIxs({ signer: claimer })),
|
|
998
|
+
],
|
|
999
|
+
setupIxs: [tokenBaseClaimerAtaIx, tokenSyClaimerAtaIx],
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
async ixWrapperBuyPt({
|
|
1004
|
+
owner,
|
|
1005
|
+
ptOut,
|
|
1006
|
+
maxBaseIn,
|
|
1007
|
+
tokenSyTrader,
|
|
1008
|
+
tokenPtTrader,
|
|
1009
|
+
tokenBaseTrader,
|
|
1010
|
+
}: {
|
|
1011
|
+
owner: web3.PublicKey
|
|
1012
|
+
ptOut: bigint
|
|
1013
|
+
maxBaseIn: bigint
|
|
1014
|
+
tokenSyTrader?: web3.PublicKey
|
|
1015
|
+
tokenPtTrader?: web3.PublicKey
|
|
1016
|
+
tokenBaseTrader?: web3.PublicKey
|
|
1017
|
+
}) {
|
|
1018
|
+
tokenSyTrader = tokenSyTrader || getAssociatedTokenAddressSync(this.mintSy, owner, true, TOKEN_PROGRAM_ID)
|
|
1019
|
+
tokenPtTrader = tokenPtTrader || getAssociatedTokenAddressSync(this.mintPt, owner, true, TOKEN_PROGRAM_ID)
|
|
1020
|
+
tokenBaseTrader =
|
|
1021
|
+
tokenBaseTrader || getAssociatedTokenAddressSync(this.flavor.mintBase, owner, true, this.flavor.baseTokenProgram)
|
|
1022
|
+
|
|
1023
|
+
const tokenSyTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1024
|
+
owner,
|
|
1025
|
+
tokenSyTrader,
|
|
1026
|
+
owner,
|
|
1027
|
+
this.mintSy,
|
|
1028
|
+
)
|
|
1029
|
+
const tokenPtTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1030
|
+
owner,
|
|
1031
|
+
tokenPtTrader,
|
|
1032
|
+
owner,
|
|
1033
|
+
this.mintPt,
|
|
1034
|
+
)
|
|
1035
|
+
const tokenBaseTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1036
|
+
owner,
|
|
1037
|
+
tokenBaseTrader,
|
|
1038
|
+
owner,
|
|
1039
|
+
this.flavor.mintBase,
|
|
1040
|
+
)
|
|
1041
|
+
|
|
1042
|
+
const mintSyIx = await this.flavor.ixMintSy({
|
|
1043
|
+
amountBase: "0",
|
|
1044
|
+
depositor: owner,
|
|
1045
|
+
depositorBaseTokenAccount: tokenBaseTrader,
|
|
1046
|
+
depositorSyTokenAccount: tokenSyTrader,
|
|
1047
|
+
})
|
|
1048
|
+
|
|
1049
|
+
const mintSyRemAccounts = mintSyIx.keys
|
|
1050
|
+
|
|
1051
|
+
console.log("mintSyRemAccounts", mintSyRemAccounts)
|
|
1052
|
+
|
|
1053
|
+
mintSyRemAccounts.push({
|
|
1054
|
+
pubkey: this.coreProgram.programId,
|
|
1055
|
+
isWritable: false,
|
|
1056
|
+
isSigner: false,
|
|
1057
|
+
})
|
|
1058
|
+
|
|
1059
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
1060
|
+
...this.cpiAccounts.getSyState,
|
|
1061
|
+
...this.cpiAccounts.depositSy,
|
|
1062
|
+
// ...this.cpiAccounts.withdrawSy,
|
|
1063
|
+
])
|
|
1064
|
+
|
|
1065
|
+
const ix = await this.coreProgram.methods
|
|
1066
|
+
.wrapperBuyPt(new BN(ptOut.toString()), new BN(maxBaseIn.toString()), mintSyRemAccounts.length)
|
|
1067
|
+
.accountsStrict({
|
|
1068
|
+
addressLookupTable: this.addressLookupTable,
|
|
1069
|
+
buyer: owner,
|
|
1070
|
+
market: this.selfAddress,
|
|
1071
|
+
tokenSyTrader,
|
|
1072
|
+
tokenPtTrader,
|
|
1073
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1074
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1075
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1076
|
+
syProgram: this.syProgram,
|
|
1077
|
+
tokenFeeTreasurySy: this.state.tokenFeeTreasurySy,
|
|
1078
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1079
|
+
program: this.coreProgram.programId,
|
|
1080
|
+
})
|
|
1081
|
+
.remainingAccounts(mintSyRemAccounts.concat(remainingAccounts))
|
|
1082
|
+
.instruction()
|
|
1083
|
+
|
|
1084
|
+
return {
|
|
1085
|
+
ixs: [...(await this.flavor.preIxs({ signer: owner })), ix, ...(await this.flavor.postIxs({ signer: owner }))],
|
|
1086
|
+
setupIxs: [tokenSyTraderAtaIx, tokenPtTraderAtaIx, tokenBaseTraderAtaIx],
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
async ixWrapperSellPt({
|
|
1091
|
+
owner,
|
|
1092
|
+
amount,
|
|
1093
|
+
minBaseOut,
|
|
1094
|
+
tokenSyTrader,
|
|
1095
|
+
tokenPtTrader,
|
|
1096
|
+
tokenBaseTrader,
|
|
1097
|
+
}: {
|
|
1098
|
+
owner: web3.PublicKey
|
|
1099
|
+
amount: bigint
|
|
1100
|
+
minBaseOut: bigint
|
|
1101
|
+
tokenSyTrader?: web3.PublicKey
|
|
1102
|
+
tokenPtTrader?: web3.PublicKey
|
|
1103
|
+
tokenBaseTrader?: web3.PublicKey
|
|
1104
|
+
}) {
|
|
1105
|
+
tokenSyTrader = tokenSyTrader || getAssociatedTokenAddressSync(this.mintSy, owner, true, TOKEN_PROGRAM_ID)
|
|
1106
|
+
tokenPtTrader = tokenPtTrader || getAssociatedTokenAddressSync(this.mintPt, owner, true, TOKEN_PROGRAM_ID)
|
|
1107
|
+
tokenBaseTrader =
|
|
1108
|
+
tokenBaseTrader || getAssociatedTokenAddressSync(this.flavor.mintBase, owner, true, this.flavor.baseTokenProgram)
|
|
1109
|
+
|
|
1110
|
+
const tokenSyTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1111
|
+
owner,
|
|
1112
|
+
tokenSyTrader,
|
|
1113
|
+
owner,
|
|
1114
|
+
this.mintSy,
|
|
1115
|
+
)
|
|
1116
|
+
const tokenPtTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1117
|
+
owner,
|
|
1118
|
+
tokenPtTrader,
|
|
1119
|
+
owner,
|
|
1120
|
+
this.mintPt,
|
|
1121
|
+
)
|
|
1122
|
+
const tokenBaseTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1123
|
+
owner,
|
|
1124
|
+
tokenBaseTrader,
|
|
1125
|
+
owner,
|
|
1126
|
+
this.flavor.mintBase,
|
|
1127
|
+
)
|
|
1128
|
+
|
|
1129
|
+
const redeemSyIx = await this.flavor.ixRedeemSy({
|
|
1130
|
+
amountSy: "0",
|
|
1131
|
+
redeemer: owner,
|
|
1132
|
+
redeemerBaseTokenAccount: tokenBaseTrader,
|
|
1133
|
+
redeemerSyTokenAccount: tokenSyTrader,
|
|
1134
|
+
})
|
|
1135
|
+
|
|
1136
|
+
const redeemSyRemAccounts = redeemSyIx.keys
|
|
1137
|
+
redeemSyRemAccounts.push({
|
|
1138
|
+
pubkey: this.coreProgram.programId,
|
|
1139
|
+
isWritable: false,
|
|
1140
|
+
isSigner: false,
|
|
1141
|
+
})
|
|
1142
|
+
|
|
1143
|
+
const remainingAccounts = uniqueRemainingAccounts([...this.cpiAccounts.getSyState, ...this.cpiAccounts.withdrawSy])
|
|
1144
|
+
|
|
1145
|
+
const ix = await this.coreProgram.methods
|
|
1146
|
+
.wrapperSellPt(new BN(amount.toString()), new BN(minBaseOut.toString()), redeemSyRemAccounts.length)
|
|
1147
|
+
.accountsStrict({
|
|
1148
|
+
seller: owner,
|
|
1149
|
+
market: this.selfAddress,
|
|
1150
|
+
tokenPtTrader,
|
|
1151
|
+
addressLookupTable: this.addressLookupTable,
|
|
1152
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1153
|
+
syProgram: this.syProgram,
|
|
1154
|
+
tokenSyTrader,
|
|
1155
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1156
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1157
|
+
tokenFeeTreasurySy: this.state.tokenFeeTreasurySy,
|
|
1158
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1159
|
+
program: this.coreProgram.programId,
|
|
1160
|
+
})
|
|
1161
|
+
.remainingAccounts(redeemSyRemAccounts.concat(remainingAccounts))
|
|
1162
|
+
.instruction()
|
|
1163
|
+
|
|
1164
|
+
return {
|
|
1165
|
+
ixs: [...(await this.flavor.preIxs({ signer: owner })), ix, ...(await this.flavor.postIxs({ signer: owner }))],
|
|
1166
|
+
setupIxs: [tokenSyTraderAtaIx, tokenPtTraderAtaIx, tokenBaseTraderAtaIx],
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
async ixWrapperBuyYt({
|
|
1171
|
+
owner,
|
|
1172
|
+
ytOut,
|
|
1173
|
+
maxBaseIn,
|
|
1174
|
+
tokenSyTrader,
|
|
1175
|
+
tokenPtTrader,
|
|
1176
|
+
tokenYtTrader,
|
|
1177
|
+
tokenBaseTrader,
|
|
1178
|
+
}: {
|
|
1179
|
+
owner: web3.PublicKey
|
|
1180
|
+
ytOut: bigint
|
|
1181
|
+
maxBaseIn: bigint
|
|
1182
|
+
tokenSyTrader?: web3.PublicKey
|
|
1183
|
+
tokenPtTrader?: web3.PublicKey
|
|
1184
|
+
tokenYtTrader?: web3.PublicKey
|
|
1185
|
+
tokenBaseTrader?: web3.PublicKey
|
|
1186
|
+
}) {
|
|
1187
|
+
tokenSyTrader = tokenSyTrader || getAssociatedTokenAddressSync(this.mintSy, owner, true, TOKEN_PROGRAM_ID)
|
|
1188
|
+
tokenPtTrader = tokenPtTrader || getAssociatedTokenAddressSync(this.mintPt, owner, true, TOKEN_PROGRAM_ID)
|
|
1189
|
+
tokenYtTrader = tokenYtTrader || getAssociatedTokenAddressSync(this.mintYt, owner, true, TOKEN_PROGRAM_ID)
|
|
1190
|
+
tokenBaseTrader =
|
|
1191
|
+
tokenBaseTrader || getAssociatedTokenAddressSync(this.flavor.mintBase, owner, true, this.flavor.baseTokenProgram)
|
|
1192
|
+
|
|
1193
|
+
const tokenSyTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1194
|
+
owner,
|
|
1195
|
+
tokenSyTrader,
|
|
1196
|
+
owner,
|
|
1197
|
+
this.mintSy,
|
|
1198
|
+
)
|
|
1199
|
+
const tokenPtTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1200
|
+
owner,
|
|
1201
|
+
tokenPtTrader,
|
|
1202
|
+
owner,
|
|
1203
|
+
this.mintPt,
|
|
1204
|
+
)
|
|
1205
|
+
const tokenYtTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1206
|
+
owner,
|
|
1207
|
+
tokenYtTrader,
|
|
1208
|
+
owner,
|
|
1209
|
+
this.mintYt,
|
|
1210
|
+
)
|
|
1211
|
+
|
|
1212
|
+
const mintSyIx = await this.flavor.ixMintSy({
|
|
1213
|
+
amountBase: "0",
|
|
1214
|
+
depositor: owner,
|
|
1215
|
+
depositorBaseTokenAccount: tokenBaseTrader,
|
|
1216
|
+
depositorSyTokenAccount: tokenSyTrader,
|
|
1217
|
+
})
|
|
1218
|
+
|
|
1219
|
+
const mintSyRemAccounts = mintSyIx.keys
|
|
1220
|
+
|
|
1221
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
1222
|
+
...this.cpiAccounts.getSyState,
|
|
1223
|
+
...this.vault.cpiAccounts.depositSy,
|
|
1224
|
+
...this.vault.cpiAccounts.getSyState,
|
|
1225
|
+
...this.cpiAccounts.withdrawSy,
|
|
1226
|
+
...this.cpiAccounts.getPositionState,
|
|
1227
|
+
])
|
|
1228
|
+
|
|
1229
|
+
const allRemainingAccounts = mintSyRemAccounts.concat(remainingAccounts)
|
|
1230
|
+
|
|
1231
|
+
const ix1 = await this.coreProgram.methods
|
|
1232
|
+
.wrapperBuyYt(new BN(ytOut.toString()), new BN(maxBaseIn.toString()), mintSyRemAccounts.length)
|
|
1233
|
+
.accountsStrict({
|
|
1234
|
+
buyer: owner,
|
|
1235
|
+
market: this.selfAddress,
|
|
1236
|
+
tokenSyTrader,
|
|
1237
|
+
tokenYtTrader,
|
|
1238
|
+
tokenPtTrader,
|
|
1239
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1240
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1241
|
+
marketAddressLookupTable: this.addressLookupTable,
|
|
1242
|
+
vault: this.vault.selfAddress,
|
|
1243
|
+
vaultAuthority: this.vault.authority,
|
|
1244
|
+
tokenSyEscrowVault: this.vault.escrowSy,
|
|
1245
|
+
vaultAddressLookupTable: this.vault.addressLookupTable,
|
|
1246
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1247
|
+
syProgram: this.syProgram,
|
|
1248
|
+
mintPt: this.vault.mintPt,
|
|
1249
|
+
yieldPosition: this.vault.state.yieldPositonAddress,
|
|
1250
|
+
mintYt: this.vault.mintYt,
|
|
1251
|
+
escrowYt: this.vault.escrowYt,
|
|
1252
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1253
|
+
userYieldPosition: this.xponPda.yieldPosition({ vault: this.vault.selfAddress, owner }),
|
|
1254
|
+
tokenFeeTreasurySy: this.state.tokenFeeTreasurySy,
|
|
1255
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1256
|
+
program: this.coreProgram.programId,
|
|
1257
|
+
})
|
|
1258
|
+
.remainingAccounts(allRemainingAccounts)
|
|
1259
|
+
.instruction()
|
|
1260
|
+
|
|
1261
|
+
const ix2 = await this.coreProgram.methods
|
|
1262
|
+
.depositYt(new BN(ytOut.toString()))
|
|
1263
|
+
.accountsStrict({
|
|
1264
|
+
depositor: owner,
|
|
1265
|
+
vault: this.vault.selfAddress,
|
|
1266
|
+
userYieldPosition: this.xponPda.yieldPosition({ vault: this.vault.selfAddress, owner }),
|
|
1267
|
+
ytSrc: tokenYtTrader,
|
|
1268
|
+
escrowYt: this.vault.escrowYt,
|
|
1269
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1270
|
+
syProgram: this.syProgram,
|
|
1271
|
+
addressLookupTable: this.vault.addressLookupTable,
|
|
1272
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1273
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1274
|
+
program: this.coreProgram.programId,
|
|
1275
|
+
yieldPosition: this.vault.state.yieldPositonAddress,
|
|
1276
|
+
})
|
|
1277
|
+
.remainingAccounts(remainingAccounts)
|
|
1278
|
+
.instruction()
|
|
1279
|
+
|
|
1280
|
+
return {
|
|
1281
|
+
ixs: [
|
|
1282
|
+
...(await this.flavor.preIxs({ signer: owner })),
|
|
1283
|
+
ix1,
|
|
1284
|
+
...(await this.flavor.postIxs({ signer: owner })),
|
|
1285
|
+
ix2,
|
|
1286
|
+
],
|
|
1287
|
+
setupIxs: [tokenSyTraderAtaIx, tokenPtTraderAtaIx, tokenYtTraderAtaIx],
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
async ixWrapperSellYt({
|
|
1292
|
+
owner,
|
|
1293
|
+
amount,
|
|
1294
|
+
minBaseOut,
|
|
1295
|
+
tokenBaseTrader,
|
|
1296
|
+
tokenSyTrader,
|
|
1297
|
+
tokenYtTrader,
|
|
1298
|
+
tokenPtTrader,
|
|
1299
|
+
}: {
|
|
1300
|
+
owner: web3.PublicKey
|
|
1301
|
+
amount: bigint
|
|
1302
|
+
minBaseOut: bigint
|
|
1303
|
+
tokenBaseTrader?: web3.PublicKey
|
|
1304
|
+
tokenSyTrader?: web3.PublicKey
|
|
1305
|
+
tokenYtTrader?: web3.PublicKey
|
|
1306
|
+
tokenPtTrader?: web3.PublicKey
|
|
1307
|
+
}) {
|
|
1308
|
+
tokenBaseTrader =
|
|
1309
|
+
tokenBaseTrader || getAssociatedTokenAddressSync(this.flavor.mintBase, owner, true, this.flavor.baseTokenProgram)
|
|
1310
|
+
tokenSyTrader = tokenSyTrader || getAssociatedTokenAddressSync(this.mintSy, owner, true, TOKEN_PROGRAM_ID)
|
|
1311
|
+
tokenYtTrader = tokenYtTrader || getAssociatedTokenAddressSync(this.mintYt, owner, true, TOKEN_PROGRAM_ID)
|
|
1312
|
+
tokenPtTrader = tokenPtTrader || getAssociatedTokenAddressSync(this.mintPt, owner, true, TOKEN_PROGRAM_ID)
|
|
1313
|
+
|
|
1314
|
+
const tokenSyTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1315
|
+
owner,
|
|
1316
|
+
tokenSyTrader,
|
|
1317
|
+
owner,
|
|
1318
|
+
this.mintSy,
|
|
1319
|
+
)
|
|
1320
|
+
const tokenPtTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1321
|
+
owner,
|
|
1322
|
+
tokenPtTrader,
|
|
1323
|
+
owner,
|
|
1324
|
+
this.mintPt,
|
|
1325
|
+
)
|
|
1326
|
+
const tokenYtTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1327
|
+
owner,
|
|
1328
|
+
tokenYtTrader,
|
|
1329
|
+
owner,
|
|
1330
|
+
this.mintYt,
|
|
1331
|
+
)
|
|
1332
|
+
const tokenBaseTraderAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1333
|
+
owner,
|
|
1334
|
+
tokenBaseTrader,
|
|
1335
|
+
owner,
|
|
1336
|
+
this.flavor.mintBase,
|
|
1337
|
+
)
|
|
1338
|
+
|
|
1339
|
+
const redeemSyIx = await this.flavor.ixRedeemSy({
|
|
1340
|
+
amountSy: "0",
|
|
1341
|
+
redeemer: owner,
|
|
1342
|
+
redeemerBaseTokenAccount: tokenBaseTrader,
|
|
1343
|
+
redeemerSyTokenAccount: tokenSyTrader,
|
|
1344
|
+
})
|
|
1345
|
+
|
|
1346
|
+
const redeemSyRemAccounts = redeemSyIx.keys
|
|
1347
|
+
|
|
1348
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
1349
|
+
...this.cpiAccounts.getSyState,
|
|
1350
|
+
...this.cpiAccounts.withdrawSy,
|
|
1351
|
+
...this.vault.cpiAccounts.depositSy,
|
|
1352
|
+
])
|
|
1353
|
+
|
|
1354
|
+
console.log(" remaining accounts length", remainingAccounts.length)
|
|
1355
|
+
|
|
1356
|
+
// remainingAccounts.push({
|
|
1357
|
+
// pubkey: this.coreProgram.programId,
|
|
1358
|
+
// isWritable: false,
|
|
1359
|
+
// isSigner: false,
|
|
1360
|
+
// })
|
|
1361
|
+
|
|
1362
|
+
const ix1 = await this.coreProgram.methods
|
|
1363
|
+
.withdrawYt(new BN(amount.toString()))
|
|
1364
|
+
.accountsStrict({
|
|
1365
|
+
ytDst: tokenYtTrader,
|
|
1366
|
+
escrowYt: this.vault.escrowYt,
|
|
1367
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1368
|
+
syProgram: this.syProgram,
|
|
1369
|
+
addressLookupTable: this.vault.addressLookupTable,
|
|
1370
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1371
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1372
|
+
program: this.coreProgram.programId,
|
|
1373
|
+
yieldPosition: this.vault.state.yieldPositonAddress,
|
|
1374
|
+
userYieldPosition: this.xponPda.yieldPosition({ vault: this.vault.selfAddress, owner }),
|
|
1375
|
+
authority: this.vault.authority,
|
|
1376
|
+
owner,
|
|
1377
|
+
vault: this.vault.selfAddress,
|
|
1378
|
+
})
|
|
1379
|
+
.remainingAccounts(remainingAccounts)
|
|
1380
|
+
.instruction()
|
|
1381
|
+
|
|
1382
|
+
const ix2 = await this.coreProgram.methods
|
|
1383
|
+
.wrapperSellYt(new BN(amount.toString()), new BN(minBaseOut.toString()), redeemSyRemAccounts.length)
|
|
1384
|
+
.accountsStrict({
|
|
1385
|
+
seller: owner,
|
|
1386
|
+
market: this.selfAddress,
|
|
1387
|
+
tokenYtTrader,
|
|
1388
|
+
marketAddressLookupTable: this.addressLookupTable,
|
|
1389
|
+
vault: this.vault.selfAddress,
|
|
1390
|
+
vaultAuthority: this.vault.authority,
|
|
1391
|
+
tokenPtTrader,
|
|
1392
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1393
|
+
tokenSyEscrowVault: this.vault.escrowSy,
|
|
1394
|
+
vaultAddressLookupTable: this.vault.addressLookupTable,
|
|
1395
|
+
yieldPosition: this.vault.state.yieldPositonAddress,
|
|
1396
|
+
mintPt: this.vault.mintPt,
|
|
1397
|
+
mintYt: this.vault.mintYt,
|
|
1398
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1399
|
+
syProgram: this.syProgram,
|
|
1400
|
+
tokenSyTrader,
|
|
1401
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1402
|
+
tokenFeeTreasurySy: this.state.tokenFeeTreasurySy,
|
|
1403
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1404
|
+
program: this.coreProgram.programId,
|
|
1405
|
+
})
|
|
1406
|
+
.remainingAccounts(redeemSyRemAccounts.concat(remainingAccounts))
|
|
1407
|
+
.instruction()
|
|
1408
|
+
|
|
1409
|
+
return {
|
|
1410
|
+
ixs: [
|
|
1411
|
+
ix1,
|
|
1412
|
+
...(await this.flavor.preIxs({ signer: owner })),
|
|
1413
|
+
ix2,
|
|
1414
|
+
...(await this.flavor.postIxs({ signer: owner })),
|
|
1415
|
+
],
|
|
1416
|
+
setupIxs: [tokenSyTraderAtaIx, tokenPtTraderAtaIx, tokenYtTraderAtaIx, tokenBaseTraderAtaIx],
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
async ixCollectMarketEmission({
|
|
1421
|
+
owner,
|
|
1422
|
+
emissionIndex,
|
|
1423
|
+
emissionDst,
|
|
1424
|
+
}: {
|
|
1425
|
+
owner: web3.PublicKey
|
|
1426
|
+
emissionIndex: number
|
|
1427
|
+
emissionDst?: web3.PublicKey
|
|
1428
|
+
}) {
|
|
1429
|
+
const emission = this.emissions[emissionIndex]
|
|
1430
|
+
const tokenEmissionDst =
|
|
1431
|
+
emissionDst || getAssociatedTokenAddressSync(emission.mint, owner, true, emission.tokenProgramAddress)
|
|
1432
|
+
|
|
1433
|
+
const tokenEmissionDstIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1434
|
+
owner,
|
|
1435
|
+
tokenEmissionDst,
|
|
1436
|
+
owner,
|
|
1437
|
+
emission.mint,
|
|
1438
|
+
)
|
|
1439
|
+
const ix = await this.coreProgram.methods
|
|
1440
|
+
.marketCollectEmission(emissionIndex)
|
|
1441
|
+
.accountsStrict({
|
|
1442
|
+
addressLookupTable: this.addressLookupTable,
|
|
1443
|
+
lpPosition: this.xponPda.marketLpPosition({ market: this.selfAddress, owner }),
|
|
1444
|
+
market: this.selfAddress,
|
|
1445
|
+
owner,
|
|
1446
|
+
syProgram: this.syProgram,
|
|
1447
|
+
tokenEmissionDst,
|
|
1448
|
+
tokenEmissionEscrow: this.marketEmissions.trackers[emissionIndex].tokenEscrow,
|
|
1449
|
+
tokenProgram: emission.tokenProgramAddress,
|
|
1450
|
+
program: this.coreProgram.programId,
|
|
1451
|
+
eventAuthority: this.eventAuthority,
|
|
1452
|
+
})
|
|
1453
|
+
.remainingAccounts(this.cpiAccounts.claimEmission[emissionIndex])
|
|
1454
|
+
.instruction()
|
|
1455
|
+
|
|
1456
|
+
return {
|
|
1457
|
+
ixs: [ix],
|
|
1458
|
+
setupIxs: [tokenEmissionDstIx],
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
/** Provide liquidity from a base asset - and receive YT and LP tokens in return */
|
|
1463
|
+
async ixProvideLiquidityNoPriceImpact({
|
|
1464
|
+
depositor,
|
|
1465
|
+
amountBase,
|
|
1466
|
+
minLpOut,
|
|
1467
|
+
tokenSyDepositor,
|
|
1468
|
+
tokenYtDepositor,
|
|
1469
|
+
tokenPtDepositor,
|
|
1470
|
+
tokenBaseDepositor,
|
|
1471
|
+
tokenLpDepositor,
|
|
1472
|
+
}: {
|
|
1473
|
+
depositor: web3.PublicKey
|
|
1474
|
+
amountBase: bigint
|
|
1475
|
+
minLpOut: bigint
|
|
1476
|
+
tokenSyDepositor?: web3.PublicKey
|
|
1477
|
+
tokenYtDepositor?: web3.PublicKey
|
|
1478
|
+
tokenPtDepositor?: web3.PublicKey
|
|
1479
|
+
tokenBaseDepositor?: web3.PublicKey
|
|
1480
|
+
tokenLpDepositor?: web3.PublicKey
|
|
1481
|
+
}) {
|
|
1482
|
+
tokenSyDepositor = tokenSyDepositor || getAssociatedTokenAddressSync(this.mintSy, depositor, true, TOKEN_PROGRAM_ID)
|
|
1483
|
+
tokenYtDepositor = tokenYtDepositor || getAssociatedTokenAddressSync(this.mintYt, depositor, true, TOKEN_PROGRAM_ID)
|
|
1484
|
+
tokenPtDepositor = tokenPtDepositor || getAssociatedTokenAddressSync(this.mintPt, depositor, true, TOKEN_PROGRAM_ID)
|
|
1485
|
+
tokenBaseDepositor =
|
|
1486
|
+
tokenBaseDepositor ||
|
|
1487
|
+
getAssociatedTokenAddressSync(this.flavor.mintBase, depositor, true, this.flavor.baseTokenProgram)
|
|
1488
|
+
tokenLpDepositor = tokenLpDepositor || getAssociatedTokenAddressSync(this.mintLp, depositor, true, TOKEN_PROGRAM_ID)
|
|
1489
|
+
|
|
1490
|
+
const tokenSyDepositorAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1491
|
+
depositor,
|
|
1492
|
+
tokenSyDepositor,
|
|
1493
|
+
depositor,
|
|
1494
|
+
this.mintSy,
|
|
1495
|
+
)
|
|
1496
|
+
const tokenYtDepositorAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1497
|
+
depositor,
|
|
1498
|
+
tokenYtDepositor,
|
|
1499
|
+
depositor,
|
|
1500
|
+
this.mintYt,
|
|
1501
|
+
)
|
|
1502
|
+
const tokenPtDepositorAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1503
|
+
depositor,
|
|
1504
|
+
tokenPtDepositor,
|
|
1505
|
+
depositor,
|
|
1506
|
+
this.mintPt,
|
|
1507
|
+
)
|
|
1508
|
+
|
|
1509
|
+
const tokenLpDepositorAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1510
|
+
depositor,
|
|
1511
|
+
tokenLpDepositor,
|
|
1512
|
+
depositor,
|
|
1513
|
+
this.mintLp,
|
|
1514
|
+
)
|
|
1515
|
+
|
|
1516
|
+
const amountBaseBn = new BN(amountBase.toString())
|
|
1517
|
+
const minLpOutBn = new BN(minLpOut.toString())
|
|
1518
|
+
|
|
1519
|
+
// TODO - fix this
|
|
1520
|
+
const mintSyIx = await this.flavor.ixMintSy({
|
|
1521
|
+
// argument does not matter - since we are just getting the keys
|
|
1522
|
+
amountBase: "0",
|
|
1523
|
+
depositor,
|
|
1524
|
+
depositorBaseTokenAccount: tokenBaseDepositor,
|
|
1525
|
+
depositorSyTokenAccount: tokenSyDepositor,
|
|
1526
|
+
})
|
|
1527
|
+
|
|
1528
|
+
const mintSyRemAccounts = mintSyIx.keys
|
|
1529
|
+
|
|
1530
|
+
// Log vault accounts before filtering
|
|
1531
|
+
const beforeVaultAccounts = [...this.vault.cpiAccounts.getSyState, ...this.vault.cpiAccounts.depositSy]
|
|
1532
|
+
console.log("Before filtering vault accounts:", beforeVaultAccounts.length, "accounts")
|
|
1533
|
+
|
|
1534
|
+
// Filter out TOKEN_PROGRAM_ID and SystemProgram.programId from vault remaining accounts
|
|
1535
|
+
const vaultCpiRemainingAccounts = beforeVaultAccounts.filter(
|
|
1536
|
+
(account) => account.pubkey.toBase58() !== TOKEN_PROGRAM_ID.toBase58(),
|
|
1537
|
+
)
|
|
1538
|
+
|
|
1539
|
+
// Log vault accounts after filtering
|
|
1540
|
+
console.log("After filtering vault accounts:", vaultCpiRemainingAccounts.length, "accounts")
|
|
1541
|
+
|
|
1542
|
+
// Log market accounts before filtering
|
|
1543
|
+
const beforeMarketAccounts = [...this.cpiAccounts.depositSy]
|
|
1544
|
+
console.log("Before filtering market accounts:", beforeMarketAccounts.length, "accounts")
|
|
1545
|
+
|
|
1546
|
+
// Filter out TOKEN_PROGRAM_ID and SystemProgram.programId from market remaining accounts
|
|
1547
|
+
const marketCpiRemainingAccounts = beforeMarketAccounts.filter(
|
|
1548
|
+
(account) =>
|
|
1549
|
+
account.pubkey.toBase58() !== TOKEN_PROGRAM_ID.toBase58() &&
|
|
1550
|
+
account.pubkey.toBase58() !== web3.SystemProgram.programId.toBase58() &&
|
|
1551
|
+
account.pubkey.toBase58() !== this.selfAddress.toBase58(),
|
|
1552
|
+
)
|
|
1553
|
+
|
|
1554
|
+
// Log market accounts after filtering
|
|
1555
|
+
console.log("After filtering market accounts:", marketCpiRemainingAccounts.length, "accounts")
|
|
1556
|
+
|
|
1557
|
+
// These remaining accounts can be in any order, and they can be unique-ified
|
|
1558
|
+
const unorderedRemainingAccounts = uniqueRemainingAccounts([
|
|
1559
|
+
...vaultCpiRemainingAccounts,
|
|
1560
|
+
...marketCpiRemainingAccounts,
|
|
1561
|
+
])
|
|
1562
|
+
|
|
1563
|
+
const allRemainingAccounts = [...mintSyRemAccounts, ...unorderedRemainingAccounts]
|
|
1564
|
+
|
|
1565
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner: depositor })
|
|
1566
|
+
|
|
1567
|
+
const ix = await this.coreProgram.methods
|
|
1568
|
+
.wrapperProvideLiquidity(amountBaseBn, minLpOutBn, mintSyRemAccounts.length)
|
|
1569
|
+
.accountsStrict({
|
|
1570
|
+
depositor,
|
|
1571
|
+
authority: this.vault.authority,
|
|
1572
|
+
vault: this.vault.selfAddress,
|
|
1573
|
+
market: this.selfAddress,
|
|
1574
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1575
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1576
|
+
tokenLpDst: tokenLpDepositor,
|
|
1577
|
+
mintLp: this.mintLp,
|
|
1578
|
+
escrowSy: this.vault.escrowSy,
|
|
1579
|
+
escrowYt: this.vault.escrowYt,
|
|
1580
|
+
tokenSyDepositor,
|
|
1581
|
+
tokenYtDepositor,
|
|
1582
|
+
tokenPtDepositor,
|
|
1583
|
+
mintYt: this.vault.mintYt,
|
|
1584
|
+
mintPt: this.vault.mintPt,
|
|
1585
|
+
userYieldPosition: this.xponPda.yieldPosition({ vault: this.vault.selfAddress, owner: depositor }),
|
|
1586
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1587
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1588
|
+
syProgram: this.syProgram,
|
|
1589
|
+
marketAddressLookupTable: this.addressLookupTable,
|
|
1590
|
+
vaultAddressLookupTable: this.vault.addressLookupTable,
|
|
1591
|
+
vaultRobotYieldPosition: this.vault.state.yieldPositonAddress,
|
|
1592
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1593
|
+
program: this.coreProgram.programId,
|
|
1594
|
+
lpPosition,
|
|
1595
|
+
tokenLpEscrow: this.tokenLpEscrow,
|
|
1596
|
+
})
|
|
1597
|
+
.remainingAccounts(allRemainingAccounts)
|
|
1598
|
+
.instruction()
|
|
1599
|
+
|
|
1600
|
+
console.log("ix accounts length", ix.keys.length)
|
|
1601
|
+
|
|
1602
|
+
return {
|
|
1603
|
+
ixs: [
|
|
1604
|
+
...(await this.flavor.preIxs({ signer: depositor })),
|
|
1605
|
+
ix,
|
|
1606
|
+
...(await this.flavor.postIxs({ signer: depositor })),
|
|
1607
|
+
],
|
|
1608
|
+
setupIxs: [tokenSyDepositorAtaIx, tokenYtDepositorAtaIx, tokenPtDepositorAtaIx, tokenLpDepositorAtaIx],
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
async ixProvideLiquidityBase({
|
|
1613
|
+
depositor,
|
|
1614
|
+
amountBase,
|
|
1615
|
+
minLpOut,
|
|
1616
|
+
externalPtToBuy,
|
|
1617
|
+
externalSyConstraint,
|
|
1618
|
+
tokenSyDepositor,
|
|
1619
|
+
tokenYtDepositor,
|
|
1620
|
+
tokenPtDepositor,
|
|
1621
|
+
tokenBaseDepositor,
|
|
1622
|
+
tokenLpDepositor,
|
|
1623
|
+
}: {
|
|
1624
|
+
depositor: web3.PublicKey
|
|
1625
|
+
amountBase: bigint
|
|
1626
|
+
minLpOut: bigint
|
|
1627
|
+
externalPtToBuy: bigint
|
|
1628
|
+
externalSyConstraint: bigint
|
|
1629
|
+
tokenSyDepositor?: web3.PublicKey
|
|
1630
|
+
tokenYtDepositor?: web3.PublicKey
|
|
1631
|
+
tokenPtDepositor?: web3.PublicKey
|
|
1632
|
+
tokenBaseDepositor?: web3.PublicKey
|
|
1633
|
+
tokenLpDepositor?: web3.PublicKey
|
|
1634
|
+
}) {
|
|
1635
|
+
tokenSyDepositor = tokenSyDepositor || getAssociatedTokenAddressSync(this.mintSy, depositor, true, TOKEN_PROGRAM_ID)
|
|
1636
|
+
tokenYtDepositor = tokenYtDepositor || getAssociatedTokenAddressSync(this.mintYt, depositor, true, TOKEN_PROGRAM_ID)
|
|
1637
|
+
tokenPtDepositor = tokenPtDepositor || getAssociatedTokenAddressSync(this.mintPt, depositor, true, TOKEN_PROGRAM_ID)
|
|
1638
|
+
tokenBaseDepositor =
|
|
1639
|
+
tokenBaseDepositor ||
|
|
1640
|
+
getAssociatedTokenAddressSync(this.flavor.mintBase, depositor, true, this.flavor.baseTokenProgram)
|
|
1641
|
+
tokenLpDepositor = tokenLpDepositor || getAssociatedTokenAddressSync(this.mintLp, depositor, true, TOKEN_PROGRAM_ID)
|
|
1642
|
+
|
|
1643
|
+
const tokenSyAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1644
|
+
depositor,
|
|
1645
|
+
tokenSyDepositor,
|
|
1646
|
+
depositor,
|
|
1647
|
+
this.mintSy,
|
|
1648
|
+
)
|
|
1649
|
+
const tokenYtAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1650
|
+
depositor,
|
|
1651
|
+
tokenYtDepositor,
|
|
1652
|
+
depositor,
|
|
1653
|
+
this.mintYt,
|
|
1654
|
+
)
|
|
1655
|
+
const tokenPtAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1656
|
+
depositor,
|
|
1657
|
+
tokenPtDepositor,
|
|
1658
|
+
depositor,
|
|
1659
|
+
this.mintPt,
|
|
1660
|
+
)
|
|
1661
|
+
const tokenBaseAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1662
|
+
depositor,
|
|
1663
|
+
tokenBaseDepositor,
|
|
1664
|
+
depositor,
|
|
1665
|
+
this.flavor.mintBase,
|
|
1666
|
+
this.flavor.baseTokenProgram,
|
|
1667
|
+
)
|
|
1668
|
+
const tokenLpAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1669
|
+
depositor,
|
|
1670
|
+
tokenLpDepositor,
|
|
1671
|
+
depositor,
|
|
1672
|
+
this.mintLp,
|
|
1673
|
+
)
|
|
1674
|
+
|
|
1675
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner: depositor })
|
|
1676
|
+
|
|
1677
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
1678
|
+
...this.cpiAccounts.depositSy,
|
|
1679
|
+
...this.cpiAccounts.getPositionState,
|
|
1680
|
+
])
|
|
1681
|
+
|
|
1682
|
+
const mintSyIx = await this.flavor.ixMintSy({
|
|
1683
|
+
amountBase: "0",
|
|
1684
|
+
depositor,
|
|
1685
|
+
depositorBaseTokenAccount: tokenBaseDepositor,
|
|
1686
|
+
depositorSyTokenAccount: tokenSyDepositor,
|
|
1687
|
+
})
|
|
1688
|
+
|
|
1689
|
+
const mintSyRemAccounts = mintSyIx.keys
|
|
1690
|
+
|
|
1691
|
+
const ix = await this.coreProgram.methods
|
|
1692
|
+
.wrapperProvideLiquidityBase(
|
|
1693
|
+
new BN(amountBase.toString()),
|
|
1694
|
+
new BN(minLpOut.toString()),
|
|
1695
|
+
mintSyRemAccounts.length,
|
|
1696
|
+
new BN(externalPtToBuy.toString()),
|
|
1697
|
+
new BN(externalSyConstraint.toString()),
|
|
1698
|
+
)
|
|
1699
|
+
.accountsStrict({
|
|
1700
|
+
depositor,
|
|
1701
|
+
lpPosition,
|
|
1702
|
+
market: this.selfAddress,
|
|
1703
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1704
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1705
|
+
tokenLpDst: tokenLpDepositor,
|
|
1706
|
+
mintLp: this.mintLp,
|
|
1707
|
+
syProgram: this.syProgram,
|
|
1708
|
+
tokenFeeTreasurySy: this.state.tokenFeeTreasurySy,
|
|
1709
|
+
tokenLpEscrow: this.tokenLpEscrow,
|
|
1710
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1711
|
+
marketAddressLookupTable: this.addressLookupTable,
|
|
1712
|
+
tokenPtDepositor,
|
|
1713
|
+
tokenSyDepositor,
|
|
1714
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1715
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1716
|
+
program: this.coreProgram.programId,
|
|
1717
|
+
})
|
|
1718
|
+
.remainingAccounts(mintSyRemAccounts.concat(remainingAccounts))
|
|
1719
|
+
.instruction()
|
|
1720
|
+
|
|
1721
|
+
return {
|
|
1722
|
+
ixs: [
|
|
1723
|
+
...(await this.flavor.preIxs({ signer: depositor })),
|
|
1724
|
+
ix,
|
|
1725
|
+
...(await this.flavor.postIxs({ signer: depositor })),
|
|
1726
|
+
],
|
|
1727
|
+
setupIxs: [tokenSyAtaIx, tokenYtAtaIx, tokenPtAtaIx, tokenBaseAtaIx, tokenLpAtaIx],
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
async ixProvideLiquidityClassic({
|
|
1732
|
+
depositor,
|
|
1733
|
+
amountBase,
|
|
1734
|
+
amountPt,
|
|
1735
|
+
minLpOut,
|
|
1736
|
+
tokenSyDepositor,
|
|
1737
|
+
tokenYtDepositor,
|
|
1738
|
+
tokenPtDepositor,
|
|
1739
|
+
tokenBaseDepositor,
|
|
1740
|
+
tokenLpDepositor,
|
|
1741
|
+
}: {
|
|
1742
|
+
depositor: web3.PublicKey
|
|
1743
|
+
amountBase: bigint
|
|
1744
|
+
amountPt: bigint
|
|
1745
|
+
minLpOut: bigint
|
|
1746
|
+
tokenSyDepositor?: web3.PublicKey
|
|
1747
|
+
tokenYtDepositor?: web3.PublicKey
|
|
1748
|
+
tokenPtDepositor?: web3.PublicKey
|
|
1749
|
+
tokenBaseDepositor?: web3.PublicKey
|
|
1750
|
+
tokenLpDepositor?: web3.PublicKey
|
|
1751
|
+
}) {
|
|
1752
|
+
tokenSyDepositor = tokenSyDepositor || getAssociatedTokenAddressSync(this.mintSy, depositor, true, TOKEN_PROGRAM_ID)
|
|
1753
|
+
tokenYtDepositor = tokenYtDepositor || getAssociatedTokenAddressSync(this.mintYt, depositor, true, TOKEN_PROGRAM_ID)
|
|
1754
|
+
tokenPtDepositor = tokenPtDepositor || getAssociatedTokenAddressSync(this.mintPt, depositor, true, TOKEN_PROGRAM_ID)
|
|
1755
|
+
tokenBaseDepositor =
|
|
1756
|
+
tokenBaseDepositor ||
|
|
1757
|
+
getAssociatedTokenAddressSync(this.flavor.mintBase, depositor, true, this.flavor.baseTokenProgram)
|
|
1758
|
+
tokenLpDepositor = tokenLpDepositor || getAssociatedTokenAddressSync(this.mintLp, depositor, true, TOKEN_PROGRAM_ID)
|
|
1759
|
+
|
|
1760
|
+
const tokenSyAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1761
|
+
depositor,
|
|
1762
|
+
tokenSyDepositor,
|
|
1763
|
+
depositor,
|
|
1764
|
+
this.mintSy,
|
|
1765
|
+
)
|
|
1766
|
+
|
|
1767
|
+
const tokenYtAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1768
|
+
depositor,
|
|
1769
|
+
tokenYtDepositor,
|
|
1770
|
+
depositor,
|
|
1771
|
+
this.mintYt,
|
|
1772
|
+
)
|
|
1773
|
+
|
|
1774
|
+
const tokenPtAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1775
|
+
depositor,
|
|
1776
|
+
tokenPtDepositor,
|
|
1777
|
+
depositor,
|
|
1778
|
+
this.mintPt,
|
|
1779
|
+
)
|
|
1780
|
+
|
|
1781
|
+
const tokenLpAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1782
|
+
depositor,
|
|
1783
|
+
tokenLpDepositor,
|
|
1784
|
+
depositor,
|
|
1785
|
+
this.mintLp,
|
|
1786
|
+
)
|
|
1787
|
+
|
|
1788
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner: depositor })
|
|
1789
|
+
|
|
1790
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
1791
|
+
...this.cpiAccounts.depositSy,
|
|
1792
|
+
...this.cpiAccounts.getPositionState,
|
|
1793
|
+
])
|
|
1794
|
+
|
|
1795
|
+
const mintSyIx = await this.flavor.ixMintSy({
|
|
1796
|
+
amountBase: "0",
|
|
1797
|
+
depositor,
|
|
1798
|
+
depositorBaseTokenAccount: tokenBaseDepositor,
|
|
1799
|
+
depositorSyTokenAccount: tokenSyDepositor,
|
|
1800
|
+
})
|
|
1801
|
+
|
|
1802
|
+
const mintSyRemAccounts = mintSyIx.keys
|
|
1803
|
+
|
|
1804
|
+
const ix = await this.coreProgram.methods
|
|
1805
|
+
.wrapperProvideLiquidityClassic(
|
|
1806
|
+
new BN(amountBase.toString()),
|
|
1807
|
+
new BN(amountPt.toString()),
|
|
1808
|
+
new BN(minLpOut.toString()),
|
|
1809
|
+
mintSyRemAccounts.length,
|
|
1810
|
+
)
|
|
1811
|
+
.accountsStrict({
|
|
1812
|
+
depositor,
|
|
1813
|
+
lpPosition,
|
|
1814
|
+
market: this.selfAddress,
|
|
1815
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1816
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1817
|
+
tokenLpDst: tokenLpDepositor,
|
|
1818
|
+
mintLp: this.mintLp,
|
|
1819
|
+
syProgram: this.syProgram,
|
|
1820
|
+
tokenLpEscrow: this.tokenLpEscrow,
|
|
1821
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1822
|
+
marketAddressLookupTable: this.addressLookupTable,
|
|
1823
|
+
tokenPtDepositor,
|
|
1824
|
+
tokenSyDepositor,
|
|
1825
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1826
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1827
|
+
program: this.coreProgram.programId,
|
|
1828
|
+
})
|
|
1829
|
+
.remainingAccounts(mintSyRemAccounts.concat(remainingAccounts))
|
|
1830
|
+
.instruction()
|
|
1831
|
+
|
|
1832
|
+
return {
|
|
1833
|
+
ixs: [
|
|
1834
|
+
...(await this.flavor.preIxs({ signer: depositor })),
|
|
1835
|
+
ix,
|
|
1836
|
+
...(await this.flavor.postIxs({ signer: depositor })),
|
|
1837
|
+
],
|
|
1838
|
+
setupIxs: [tokenSyAtaIx, tokenYtAtaIx, tokenPtAtaIx, tokenLpAtaIx],
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
async ixWithdrawLiquidityToBase({
|
|
1843
|
+
owner,
|
|
1844
|
+
amountLp,
|
|
1845
|
+
minBaseOut,
|
|
1846
|
+
tokenSyWithdrawer,
|
|
1847
|
+
tokenYtWithdrawer,
|
|
1848
|
+
tokenPtWithdrawer,
|
|
1849
|
+
tokenBaseWithdrawer,
|
|
1850
|
+
tokenLpWithdrawer,
|
|
1851
|
+
}: {
|
|
1852
|
+
owner: web3.PublicKey
|
|
1853
|
+
amountLp: bigint
|
|
1854
|
+
minBaseOut: bigint
|
|
1855
|
+
tokenSyWithdrawer?: web3.PublicKey
|
|
1856
|
+
tokenYtWithdrawer?: web3.PublicKey
|
|
1857
|
+
tokenPtWithdrawer?: web3.PublicKey
|
|
1858
|
+
tokenBaseWithdrawer?: web3.PublicKey
|
|
1859
|
+
tokenLpWithdrawer?: web3.PublicKey
|
|
1860
|
+
}) {
|
|
1861
|
+
tokenSyWithdrawer = tokenSyWithdrawer || getAssociatedTokenAddressSync(this.mintSy, owner, true, TOKEN_PROGRAM_ID)
|
|
1862
|
+
tokenYtWithdrawer = tokenYtWithdrawer || getAssociatedTokenAddressSync(this.mintYt, owner, true, TOKEN_PROGRAM_ID)
|
|
1863
|
+
tokenPtWithdrawer = tokenPtWithdrawer || getAssociatedTokenAddressSync(this.mintPt, owner, true, TOKEN_PROGRAM_ID)
|
|
1864
|
+
tokenBaseWithdrawer =
|
|
1865
|
+
tokenBaseWithdrawer ||
|
|
1866
|
+
getAssociatedTokenAddressSync(this.flavor.mintBase, owner, true, this.flavor.baseTokenProgram)
|
|
1867
|
+
tokenLpWithdrawer = tokenLpWithdrawer || getAssociatedTokenAddressSync(this.mintLp, owner, true, TOKEN_PROGRAM_ID)
|
|
1868
|
+
|
|
1869
|
+
const tokenSyAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenSyWithdrawer, owner, this.mintSy)
|
|
1870
|
+
const tokenYtAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenYtWithdrawer, owner, this.mintYt)
|
|
1871
|
+
const tokenPtAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenPtWithdrawer, owner, this.mintPt)
|
|
1872
|
+
const tokenBaseAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1873
|
+
owner,
|
|
1874
|
+
tokenBaseWithdrawer,
|
|
1875
|
+
owner,
|
|
1876
|
+
this.flavor.mintBase,
|
|
1877
|
+
this.flavor.baseTokenProgram,
|
|
1878
|
+
)
|
|
1879
|
+
const tokenLpAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenLpWithdrawer, owner, this.mintLp)
|
|
1880
|
+
|
|
1881
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner })
|
|
1882
|
+
|
|
1883
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
1884
|
+
...this.cpiAccounts.withdrawSy,
|
|
1885
|
+
...this.cpiAccounts.getPositionState,
|
|
1886
|
+
])
|
|
1887
|
+
|
|
1888
|
+
const redeemSyIx = await this.flavor.ixRedeemSy({
|
|
1889
|
+
amountSy: "0",
|
|
1890
|
+
redeemer: owner,
|
|
1891
|
+
redeemerBaseTokenAccount: tokenBaseWithdrawer,
|
|
1892
|
+
redeemerSyTokenAccount: tokenSyWithdrawer,
|
|
1893
|
+
})
|
|
1894
|
+
|
|
1895
|
+
const redeemSyRemAccounts = redeemSyIx.keys
|
|
1896
|
+
|
|
1897
|
+
const minSyOut = Number(minBaseOut) / this.currentSyExchangeRate
|
|
1898
|
+
|
|
1899
|
+
const ix = await this.coreProgram.methods
|
|
1900
|
+
.wrapperWithdrawLiquidity(
|
|
1901
|
+
new BN(amountLp.toString()),
|
|
1902
|
+
new BN(minSyOut.toFixed(0).toString()),
|
|
1903
|
+
redeemSyRemAccounts.length,
|
|
1904
|
+
)
|
|
1905
|
+
.accountsStrict({
|
|
1906
|
+
market: this.selfAddress,
|
|
1907
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1908
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1909
|
+
tokenLpSrc: tokenLpWithdrawer,
|
|
1910
|
+
lpPosition,
|
|
1911
|
+
marketAddressLookupTable: this.addressLookupTable,
|
|
1912
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1913
|
+
program: this.coreProgram.programId,
|
|
1914
|
+
syProgram: this.syProgram,
|
|
1915
|
+
systemProgram: web3.SystemProgram.programId,
|
|
1916
|
+
tokenFeeTreasurySy: this.state.tokenFeeTreasurySy,
|
|
1917
|
+
tokenLpEscrow: this.tokenLpEscrow,
|
|
1918
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1919
|
+
tokenPtWithdrawer,
|
|
1920
|
+
tokenSyWithdrawer,
|
|
1921
|
+
mintLp: this.mintLp,
|
|
1922
|
+
withdrawer: owner,
|
|
1923
|
+
})
|
|
1924
|
+
.remainingAccounts(redeemSyRemAccounts.concat(remainingAccounts))
|
|
1925
|
+
.instruction()
|
|
1926
|
+
|
|
1927
|
+
return {
|
|
1928
|
+
ixs: [...(await this.flavor.preIxs({ signer: owner })), ix, ...(await this.flavor.postIxs({ signer: owner }))],
|
|
1929
|
+
setupIxs: [tokenSyAtaIx, tokenYtAtaIx, tokenPtAtaIx, tokenBaseAtaIx, tokenLpAtaIx],
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
async ixWithdrawLiquidityClassic({
|
|
1934
|
+
owner,
|
|
1935
|
+
amountLp,
|
|
1936
|
+
minBaseOut,
|
|
1937
|
+
tokenSyWithdrawer,
|
|
1938
|
+
tokenYtWithdrawer,
|
|
1939
|
+
tokenPtWithdrawer,
|
|
1940
|
+
tokenBaseWithdrawer,
|
|
1941
|
+
tokenLpWithdrawer,
|
|
1942
|
+
}: {
|
|
1943
|
+
owner: web3.PublicKey
|
|
1944
|
+
amountLp: bigint
|
|
1945
|
+
minBaseOut: bigint
|
|
1946
|
+
tokenSyWithdrawer?: web3.PublicKey
|
|
1947
|
+
tokenYtWithdrawer?: web3.PublicKey
|
|
1948
|
+
tokenPtWithdrawer?: web3.PublicKey
|
|
1949
|
+
tokenBaseWithdrawer?: web3.PublicKey
|
|
1950
|
+
tokenLpWithdrawer?: web3.PublicKey
|
|
1951
|
+
}) {
|
|
1952
|
+
tokenSyWithdrawer = tokenSyWithdrawer || getAssociatedTokenAddressSync(this.mintSy, owner, true, TOKEN_PROGRAM_ID)
|
|
1953
|
+
tokenYtWithdrawer = tokenYtWithdrawer || getAssociatedTokenAddressSync(this.mintYt, owner, true, TOKEN_PROGRAM_ID)
|
|
1954
|
+
tokenPtWithdrawer = tokenPtWithdrawer || getAssociatedTokenAddressSync(this.mintPt, owner, true, TOKEN_PROGRAM_ID)
|
|
1955
|
+
tokenBaseWithdrawer =
|
|
1956
|
+
tokenBaseWithdrawer ||
|
|
1957
|
+
getAssociatedTokenAddressSync(this.flavor.mintBase, owner, true, this.flavor.baseTokenProgram)
|
|
1958
|
+
tokenLpWithdrawer = tokenLpWithdrawer || getAssociatedTokenAddressSync(this.mintLp, owner, true, TOKEN_PROGRAM_ID)
|
|
1959
|
+
|
|
1960
|
+
const tokenSyAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenSyWithdrawer, owner, this.mintSy)
|
|
1961
|
+
const tokenYtAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenYtWithdrawer, owner, this.mintYt)
|
|
1962
|
+
const tokenPtAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenPtWithdrawer, owner, this.mintPt)
|
|
1963
|
+
const tokenBaseAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
1964
|
+
owner,
|
|
1965
|
+
tokenBaseWithdrawer,
|
|
1966
|
+
owner,
|
|
1967
|
+
this.flavor.mintBase,
|
|
1968
|
+
this.flavor.baseTokenProgram,
|
|
1969
|
+
)
|
|
1970
|
+
const tokenLpAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenLpWithdrawer, owner, this.mintLp)
|
|
1971
|
+
|
|
1972
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner })
|
|
1973
|
+
|
|
1974
|
+
const remainingAccounts = uniqueRemainingAccounts([
|
|
1975
|
+
...this.cpiAccounts.withdrawSy,
|
|
1976
|
+
...this.cpiAccounts.getPositionState,
|
|
1977
|
+
])
|
|
1978
|
+
|
|
1979
|
+
const redeemSyIx = await this.flavor.ixRedeemSy({
|
|
1980
|
+
amountSy: "0",
|
|
1981
|
+
redeemer: owner,
|
|
1982
|
+
redeemerBaseTokenAccount: tokenBaseWithdrawer,
|
|
1983
|
+
redeemerSyTokenAccount: tokenSyWithdrawer,
|
|
1984
|
+
})
|
|
1985
|
+
|
|
1986
|
+
const redeemSyRemAccounts = redeemSyIx.keys
|
|
1987
|
+
|
|
1988
|
+
const ixn = await this.coreProgram.methods
|
|
1989
|
+
.wrapperWithdrawLiquidityClassic(new BN(amountLp.toString()), redeemSyRemAccounts.length)
|
|
1990
|
+
.accountsStrict({
|
|
1991
|
+
market: this.selfAddress,
|
|
1992
|
+
tokenPtEscrow: this.tokenPtEscrow,
|
|
1993
|
+
tokenSyEscrow: this.tokenSyEscrow,
|
|
1994
|
+
tokenLpSrc: tokenLpWithdrawer,
|
|
1995
|
+
lpPosition,
|
|
1996
|
+
marketAddressLookupTable: this.addressLookupTable,
|
|
1997
|
+
eventAuthority: this.vault.eventAuthority,
|
|
1998
|
+
program: this.coreProgram.programId,
|
|
1999
|
+
syProgram: this.syProgram,
|
|
2000
|
+
systemProgram: web3.SystemProgram.programId,
|
|
2001
|
+
tokenLpEscrow: this.tokenLpEscrow,
|
|
2002
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
2003
|
+
tokenPtWithdrawer,
|
|
2004
|
+
tokenSyWithdrawer,
|
|
2005
|
+
mintLp: this.mintLp,
|
|
2006
|
+
withdrawer: owner,
|
|
2007
|
+
})
|
|
2008
|
+
.remainingAccounts(redeemSyRemAccounts.concat(remainingAccounts))
|
|
2009
|
+
.instruction()
|
|
2010
|
+
|
|
2011
|
+
return {
|
|
2012
|
+
ixs: [...(await this.flavor.preIxs({ signer: owner })), ixn, ...(await this.flavor.postIxs({ signer: owner }))],
|
|
2013
|
+
setupIxs: [tokenSyAtaIx, tokenYtAtaIx, tokenPtAtaIx, tokenBaseAtaIx, tokenLpAtaIx],
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
async claimFarmEmissions({
|
|
2018
|
+
owner,
|
|
2019
|
+
mint,
|
|
2020
|
+
tokenProgram,
|
|
2021
|
+
tokenDst,
|
|
2022
|
+
}: {
|
|
2023
|
+
owner: web3.PublicKey
|
|
2024
|
+
mint: web3.PublicKey
|
|
2025
|
+
tokenProgram: web3.PublicKey
|
|
2026
|
+
tokenDst?: web3.PublicKey
|
|
2027
|
+
}) {
|
|
2028
|
+
tokenDst = tokenDst || getAssociatedTokenAddressSync(mint, owner, true, tokenProgram)
|
|
2029
|
+
const lpPosition = this.xponPda.marketLpPosition({ market: this.selfAddress, owner })
|
|
2030
|
+
|
|
2031
|
+
const tokenFarm = getAssociatedTokenAddressSync(mint, this.selfAddress, true, tokenProgram)
|
|
2032
|
+
const tokenAtaIx = createAssociatedTokenAccountIdempotentInstruction(owner, tokenDst, owner, mint)
|
|
2033
|
+
|
|
2034
|
+
const ix = await this.coreProgram.methods
|
|
2035
|
+
.claimFarmEmissions({ all: {} })
|
|
2036
|
+
.accountsStrict({
|
|
2037
|
+
market: this.selfAddress,
|
|
2038
|
+
lpPosition,
|
|
2039
|
+
mint,
|
|
2040
|
+
tokenFarm,
|
|
2041
|
+
owner,
|
|
2042
|
+
tokenDst,
|
|
2043
|
+
tokenProgram,
|
|
2044
|
+
eventAuthority: this.eventAuthority,
|
|
2045
|
+
program: this.coreProgram.programId,
|
|
2046
|
+
})
|
|
2047
|
+
.instruction()
|
|
2048
|
+
|
|
2049
|
+
return {
|
|
2050
|
+
ixs: [ix],
|
|
2051
|
+
setupIxs: [tokenAtaIx],
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
async ixAddStandaloneEmission({
|
|
2056
|
+
signer,
|
|
2057
|
+
emissionMint,
|
|
2058
|
+
emissionTokenProgram = TOKEN_PROGRAM_ID,
|
|
2059
|
+
altAddresses,
|
|
2060
|
+
cpiAccounts,
|
|
2061
|
+
}: {
|
|
2062
|
+
signer: web3.PublicKey
|
|
2063
|
+
emissionMint: web3.PublicKey
|
|
2064
|
+
emissionTokenProgram?: web3.PublicKey
|
|
2065
|
+
altAddresses: web3.PublicKey[]
|
|
2066
|
+
cpiAccounts: CpiAccountsRaw
|
|
2067
|
+
}) {
|
|
2068
|
+
const altUtil = extendAddressLookupTable(altAddresses, cpiAccounts)
|
|
2069
|
+
|
|
2070
|
+
const tokenEmission = getAssociatedTokenAddressSync(emissionMint, this.selfAddress, true, emissionTokenProgram)
|
|
2071
|
+
const ix = await this.coreProgram.methods
|
|
2072
|
+
.addMarketEmission(altUtil.cpiAccountIndexes)
|
|
2073
|
+
.accountsStrict({
|
|
2074
|
+
market: this.selfAddress,
|
|
2075
|
+
adminState: getExponentAdminStatePda(),
|
|
2076
|
+
feePayer: signer,
|
|
2077
|
+
mintNew: emissionMint,
|
|
2078
|
+
signer,
|
|
2079
|
+
systemProgram: web3.SystemProgram.programId,
|
|
2080
|
+
tokenEmission,
|
|
2081
|
+
tokenProgram: emissionTokenProgram,
|
|
2082
|
+
})
|
|
2083
|
+
.instruction()
|
|
2084
|
+
|
|
2085
|
+
return {
|
|
2086
|
+
extendAddressLookupTableExtensionAccounts: altUtil.addressLookupTableExtension,
|
|
2087
|
+
addMarketEmissionIx: ix,
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
async addFarm({
|
|
2092
|
+
signer,
|
|
2093
|
+
farmMint,
|
|
2094
|
+
farmRewardTokenProgram,
|
|
2095
|
+
emissionsRate,
|
|
2096
|
+
untilTimestamp,
|
|
2097
|
+
farmRewardSrc,
|
|
2098
|
+
feePayer,
|
|
2099
|
+
}: {
|
|
2100
|
+
signer: web3.PublicKey
|
|
2101
|
+
farmMint: web3.PublicKey
|
|
2102
|
+
farmRewardTokenProgram: web3.PublicKey
|
|
2103
|
+
emissionsRate: number
|
|
2104
|
+
untilTimestamp: number
|
|
2105
|
+
farmRewardSrc?: web3.PublicKey
|
|
2106
|
+
feePayer?: web3.PublicKey
|
|
2107
|
+
}) {
|
|
2108
|
+
feePayer = feePayer || signer
|
|
2109
|
+
const farmRewardEscrow = getAssociatedTokenAddressSync(farmMint, this.selfAddress, true, farmRewardTokenProgram)
|
|
2110
|
+
farmRewardSrc = farmRewardSrc || getAssociatedTokenAddressSync(farmMint, signer, true, farmRewardTokenProgram)
|
|
2111
|
+
|
|
2112
|
+
const ix = await this.coreProgram.methods
|
|
2113
|
+
.addFarm(new BN(emissionsRate), untilTimestamp)
|
|
2114
|
+
.accountsStrict({
|
|
2115
|
+
adminState: getExponentAdminStatePda(),
|
|
2116
|
+
market: this.selfAddress,
|
|
2117
|
+
feePayer,
|
|
2118
|
+
signer,
|
|
2119
|
+
mintNew: farmMint,
|
|
2120
|
+
tokenFarm: farmRewardEscrow,
|
|
2121
|
+
tokenProgram: farmRewardTokenProgram,
|
|
2122
|
+
systemProgram: web3.SystemProgram.programId,
|
|
2123
|
+
tokenSource: farmRewardSrc,
|
|
2124
|
+
})
|
|
2125
|
+
.instruction()
|
|
2126
|
+
|
|
2127
|
+
return {
|
|
2128
|
+
ixs: [ix],
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
/** Calculate available liquidity for PT trades
|
|
2133
|
+
* @param is_buy - true if buying PT with SY, false if selling PT for SY
|
|
2134
|
+
* @param size_pt - amount of PT to trade (in PT decimals)
|
|
2135
|
+
* @returns amount of PT that can be traded given current liquidity
|
|
2136
|
+
*/
|
|
2137
|
+
liquidityAvailable(is_buy: boolean, size_pt: bigint): bigint {
|
|
2138
|
+
const calc = this.marketCalculator()
|
|
2139
|
+
|
|
2140
|
+
if (is_buy) {
|
|
2141
|
+
// When buying PT, we're limited by SY liquidity
|
|
2142
|
+
// Convert PT amount to SY using current price
|
|
2143
|
+
const syNeeded = Number(size_pt) * calc.exchangeRate
|
|
2144
|
+
// Available SY in the market
|
|
2145
|
+
const syAvailable = Number(this.syBalance)
|
|
2146
|
+
|
|
2147
|
+
if (syNeeded <= syAvailable) {
|
|
2148
|
+
return size_pt
|
|
2149
|
+
} else {
|
|
2150
|
+
// Calculate max PT that can be bought with available SY
|
|
2151
|
+
return BigInt(Math.floor(syAvailable / calc.exchangeRate))
|
|
2152
|
+
}
|
|
2153
|
+
} else {
|
|
2154
|
+
// When selling PT, we're limited by PT liquidity in the market
|
|
2155
|
+
const ptAvailable = this.ptBalance
|
|
2156
|
+
|
|
2157
|
+
if (size_pt <= ptAvailable) {
|
|
2158
|
+
return size_pt
|
|
2159
|
+
} else {
|
|
2160
|
+
return ptAvailable
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
export type MarketJson = {
|
|
2167
|
+
/** The market's public key */
|
|
2168
|
+
address: string
|
|
2169
|
+
/** The market's address lookup table public key */
|
|
2170
|
+
addressLookupTable: string
|
|
2171
|
+
/** The market's SY escrow account public key - this is a pass-through account which moves SY between an end-user and the SY program where it is deposited and withdrawn from */
|
|
2172
|
+
tokenSyEscrow: string
|
|
2173
|
+
/** The market's PT escrow account public key - this account holds the market's PT liquidity*/
|
|
2174
|
+
tokenPtEscrow: string
|
|
2175
|
+
/** The market's LP escrow account public key - this account holds the market's LP tokens which are used to farm rewards */
|
|
2176
|
+
tokenLpEscrow: string
|
|
2177
|
+
|
|
2178
|
+
/** Token account that holds the market's SY fees */
|
|
2179
|
+
treasurySyTokenAccount: string
|
|
2180
|
+
|
|
2181
|
+
/** The market's LP supply */
|
|
2182
|
+
lpSupply: string
|
|
2183
|
+
|
|
2184
|
+
/** The SY program ID */
|
|
2185
|
+
syProgram: string
|
|
2186
|
+
|
|
2187
|
+
mintPt: string
|
|
2188
|
+
mintSy: string
|
|
2189
|
+
mintLp: string
|
|
2190
|
+
|
|
2191
|
+
/** The market's PT balance */
|
|
2192
|
+
ptBalance: string
|
|
2193
|
+
/** The market's SY balance */
|
|
2194
|
+
syBalance: string
|
|
2195
|
+
|
|
2196
|
+
/** The market's LP escrow amount */
|
|
2197
|
+
lpEscrowAmount: string
|
|
2198
|
+
|
|
2199
|
+
/** The market's current SY rate */
|
|
2200
|
+
currentSyRate: number
|
|
2201
|
+
|
|
2202
|
+
/** The market's expiration timestamp */
|
|
2203
|
+
expirationTs: number
|
|
2204
|
+
|
|
2205
|
+
/** The market's expiration date */
|
|
2206
|
+
expirationDate: string
|
|
2207
|
+
|
|
2208
|
+
/** The number of seconds remaining until the market expires */
|
|
2209
|
+
secondsRemaining: number
|
|
2210
|
+
|
|
2211
|
+
/** The market's maximum LP supply */
|
|
2212
|
+
maxLpSupply: string
|
|
2213
|
+
|
|
2214
|
+
lnFeeRateRoot: number
|
|
2215
|
+
|
|
2216
|
+
rateScalarRoot: number
|
|
2217
|
+
|
|
2218
|
+
feeTreasurySyBps: number
|
|
2219
|
+
|
|
2220
|
+
lastLnImpliedRate: number
|
|
2221
|
+
|
|
2222
|
+
/** The current rate scalar, taking into account the time decay*/
|
|
2223
|
+
currentRateScalar: number
|
|
2224
|
+
|
|
2225
|
+
/** The current rate anchor that preserves the last implied rate */
|
|
2226
|
+
currentRateAnchor: number
|
|
2227
|
+
|
|
2228
|
+
/** How many SY are required to buy 1 PT */
|
|
2229
|
+
currentPtPriceInSy: number
|
|
2230
|
+
|
|
2231
|
+
/** How many assets are required to buy 1 PT */
|
|
2232
|
+
currentPtPriceInAsset: number
|
|
2233
|
+
|
|
2234
|
+
/** Proportion of PT in terms of assets */
|
|
2235
|
+
proportionPtInAsset: number
|
|
2236
|
+
|
|
2237
|
+
/** Proportion of PT in terms of SY */
|
|
2238
|
+
proportionPtInSy: number
|
|
2239
|
+
|
|
2240
|
+
/** Current fee rate */
|
|
2241
|
+
currentFeeRate: number
|
|
2242
|
+
|
|
2243
|
+
/** CPI accounts */
|
|
2244
|
+
cpiAccounts: CpiAccountsRawJson
|
|
2245
|
+
|
|
2246
|
+
/** Annualized yield for PT */
|
|
2247
|
+
ptApr: number
|
|
2248
|
+
|
|
2249
|
+
/** Emission tokens */
|
|
2250
|
+
emissions: {
|
|
2251
|
+
trackers: {
|
|
2252
|
+
tokenEscrow: string
|
|
2253
|
+
lpShareIndex: number
|
|
2254
|
+
lastSeenStaged: number
|
|
2255
|
+
}[]
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
liquidityNetBalanceLimits: {
|
|
2259
|
+
windowStartTimestamp: number
|
|
2260
|
+
windowStartNetBalance: string
|
|
2261
|
+
maxNetBalanceChangeNegativePercentage: number
|
|
2262
|
+
maxNetBalanceChangePositivePercentage: number
|
|
2263
|
+
windowDurationSeconds: number
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
lpFarm: {
|
|
2267
|
+
lastSeenTimestamp: number
|
|
2268
|
+
farmEmissions: {
|
|
2269
|
+
mint: string
|
|
2270
|
+
/** Tokens per second */
|
|
2271
|
+
tokenRate: string
|
|
2272
|
+
expiryTimestamp: number
|
|
2273
|
+
/** Index for converting LP shares into earned emissions */
|
|
2274
|
+
index: string
|
|
2275
|
+
}[]
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
function toJson(m: Market): MarketJson {
|
|
2280
|
+
const c = m.marketCalculator()
|
|
2281
|
+
return {
|
|
2282
|
+
treasurySyTokenAccount: m.state.tokenFeeTreasurySy.toBase58(),
|
|
2283
|
+
address: m.selfAddress.toBase58(),
|
|
2284
|
+
addressLookupTable: m.addressLookupTable.toBase58(),
|
|
2285
|
+
tokenSyEscrow: m.tokenSyEscrow.toBase58(),
|
|
2286
|
+
tokenPtEscrow: m.tokenPtEscrow.toBase58(),
|
|
2287
|
+
tokenLpEscrow: m.tokenLpEscrow.toBase58(),
|
|
2288
|
+
lpSupply: m.state.lpSupply.toString(),
|
|
2289
|
+
syProgram: m.state.syProgram.toBase58(),
|
|
2290
|
+
mintPt: m.state.mintPt.toBase58(),
|
|
2291
|
+
mintSy: m.state.mintSy.toBase58(),
|
|
2292
|
+
mintLp: m.state.mintLp.toBase58(),
|
|
2293
|
+
feeTreasurySyBps: m.state.feeTreasurySyBps,
|
|
2294
|
+
ptBalance: m.state.ptBalance.toString(),
|
|
2295
|
+
syBalance: m.state.syBalance.toString(),
|
|
2296
|
+
currentSyRate: m.flavor.currentSyExchangeRate,
|
|
2297
|
+
expirationTs: m.state.expirationTs,
|
|
2298
|
+
expirationDate: new Date(m.state.expirationTs * 1000).toISOString(),
|
|
2299
|
+
lnFeeRateRoot: m.state.lnFeeRateRoot,
|
|
2300
|
+
rateScalarRoot: m.state.rateScalarRoot,
|
|
2301
|
+
lastLnImpliedRate: m.state.lastLnImpliedRate,
|
|
2302
|
+
currentPtPriceInSy: m.currentPtPriceInSy,
|
|
2303
|
+
currentPtPriceInAsset: m.currentPtPriceInAsset,
|
|
2304
|
+
secondsRemaining: m.secondsRemaining,
|
|
2305
|
+
proportionPtInAsset: c.proportionPtInAsset,
|
|
2306
|
+
proportionPtInSy: c.proportionPtInSy,
|
|
2307
|
+
currentFeeRate: c.feeRate,
|
|
2308
|
+
currentRateScalar: c.rateScalar,
|
|
2309
|
+
currentRateAnchor: c.findRateAnchor(),
|
|
2310
|
+
cpiAccounts: serializeCpiAccountsRaw(m.cpiAccounts),
|
|
2311
|
+
emissions: {
|
|
2312
|
+
trackers: m.marketEmissions.trackers.map((e) => ({
|
|
2313
|
+
tokenEscrow: e.tokenEscrow.toBase58(),
|
|
2314
|
+
lpShareIndex: e.lpShareIndex,
|
|
2315
|
+
lastSeenStaged: e.lastSeenStaged,
|
|
2316
|
+
})),
|
|
2317
|
+
},
|
|
2318
|
+
ptApr: m.ptApr,
|
|
2319
|
+
lpEscrowAmount: m.state.lpEscrowAmount.toString(),
|
|
2320
|
+
maxLpSupply: m.state.maxLpSupply.toString(),
|
|
2321
|
+
liquidityNetBalanceLimits: {
|
|
2322
|
+
windowStartTimestamp: m.state.liquidityNetBalanceLimits.windowStartTimestamp,
|
|
2323
|
+
windowStartNetBalance: m.state.liquidityNetBalanceLimits.windowStartNetBalance.toString(),
|
|
2324
|
+
maxNetBalanceChangeNegativePercentage: m.state.liquidityNetBalanceLimits.maxNetBalanceChangeNegativePercentage,
|
|
2325
|
+
maxNetBalanceChangePositivePercentage: m.state.liquidityNetBalanceLimits.maxNetBalanceChangePositivePercentage,
|
|
2326
|
+
windowDurationSeconds: m.state.liquidityNetBalanceLimits.windowDurationSeconds,
|
|
2327
|
+
},
|
|
2328
|
+
lpFarm: {
|
|
2329
|
+
lastSeenTimestamp: m.state.lpFarm.lastSeenTimestamp,
|
|
2330
|
+
farmEmissions: m.state.lpFarm.farmEmissions.map((e) => ({
|
|
2331
|
+
mint: e.mint.toBase58(),
|
|
2332
|
+
tokenRate: e.tokenRate.toString(),
|
|
2333
|
+
expiryTimestamp: e.expiryTimestamp,
|
|
2334
|
+
index: PreciseNumber.fromRaw(e.index[0]).valueString,
|
|
2335
|
+
})),
|
|
2336
|
+
},
|
|
2337
|
+
}
|
|
2338
|
+
}
|