flash-sdk 1.0.21 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/{lib → dist}/PerpetualsClient.d.ts +4 -0
  2. package/{lib → dist}/PerpetualsClient.js +121 -0
  3. package/{lib → dist}/tsconfig.tsbuildinfo +1 -1
  4. package/package.json +10 -4
  5. package/src/CustodyAccount.ts +0 -125
  6. package/src/OraclePrice.ts +0 -111
  7. package/src/PerpetualsClient.ts +0 -1961
  8. package/src/PoolAccount.ts +0 -491
  9. package/src/PoolConfig.json +0 -322
  10. package/src/PoolConfig.ts +0 -182
  11. package/src/PoolDataClient.ts +0 -173
  12. package/src/PositionAccount.ts +0 -58
  13. package/src/Token.ts +0 -1
  14. package/src/constants/index.ts +0 -21
  15. package/src/idl/perpetuals.ts +0 -7561
  16. package/src/index.ts +0 -19
  17. package/src/type-rules.md +0 -4
  18. package/src/types/index.ts +0 -290
  19. package/src/utils/index.ts +0 -234
  20. package/src/utils/rpc.ts +0 -162
  21. package/tsconfig.json +0 -23
  22. /package/{lib → dist}/CustodyAccount.d.ts +0 -0
  23. /package/{lib → dist}/CustodyAccount.js +0 -0
  24. /package/{lib → dist}/OraclePrice.d.ts +0 -0
  25. /package/{lib → dist}/OraclePrice.js +0 -0
  26. /package/{lib → dist}/PoolAccount.d.ts +0 -0
  27. /package/{lib → dist}/PoolAccount.js +0 -0
  28. /package/{lib → dist}/PoolConfig.d.ts +0 -0
  29. /package/{lib → dist}/PoolConfig.js +0 -0
  30. /package/{lib → dist}/PoolConfig.json +0 -0
  31. /package/{lib → dist}/PoolDataClient.d.ts +0 -0
  32. /package/{lib → dist}/PoolDataClient.js +0 -0
  33. /package/{lib → dist}/PositionAccount.d.ts +0 -0
  34. /package/{lib → dist}/PositionAccount.js +0 -0
  35. /package/{lib → dist}/Token.d.ts +0 -0
  36. /package/{lib → dist}/Token.js +0 -0
  37. /package/{lib → dist}/constants/index.d.ts +0 -0
  38. /package/{lib → dist}/constants/index.js +0 -0
  39. /package/{lib → dist}/idl/perpetuals.d.ts +0 -0
  40. /package/{lib → dist}/idl/perpetuals.js +0 -0
  41. /package/{lib → dist}/index.d.ts +0 -0
  42. /package/{lib → dist}/index.js +0 -0
  43. /package/{lib → dist}/types/index.d.ts +0 -0
  44. /package/{lib → dist}/types/index.js +0 -0
  45. /package/{lib → dist}/utils/index.d.ts +0 -0
  46. /package/{lib → dist}/utils/index.js +0 -0
  47. /package/{lib → dist}/utils/rpc.d.ts +0 -0
  48. /package/{lib → dist}/utils/rpc.js +0 -0
@@ -1,1961 +0,0 @@
1
- import {
2
- setProvider,
3
- Program,
4
- AnchorProvider,
5
- workspace,
6
- utils,
7
- BN,
8
- } from "@coral-xyz/anchor";
9
- import {
10
- PublicKey,
11
- TransactionInstruction,
12
- Transaction,
13
- SystemProgram,
14
- AccountMeta,
15
- Keypair,
16
- SYSVAR_RENT_PUBKEY,
17
- Commitment,
18
- LAMPORTS_PER_SOL,
19
- Signer,
20
- } from "@solana/web3.js";
21
- import {
22
- getAccount,
23
- getAssociatedTokenAddress,
24
- createAssociatedTokenAccountInstruction,
25
- createCloseAccountInstruction,
26
- createSyncNativeInstruction,
27
- TOKEN_PROGRAM_ID,
28
- NATIVE_MINT,
29
- createInitializeAccount3Instruction,
30
- getMinimumBalanceForRentExemptAccount,
31
- } from "@solana/spl-token";
32
-
33
- import { sha256 } from "js-sha256";
34
- import { encode } from "bs58";
35
- import { PoolAccount } from "./PoolAccount";
36
- import { PositionAccount } from "./PositionAccount";
37
- import { AumCalcMode, BorrowRateParams, Custody, Fees, OracleParams, Permissions, Position, PositionSide, PricingParams, Side, TokenRatios, isVariant } from "./types";
38
- import { OraclePrice } from "./OraclePrice";
39
- import { CustodyAccount } from "./CustodyAccount";
40
- import { Perpetuals } from "./idl/perpetuals";
41
- import { IDL } from './idl/perpetuals';
42
- import { sendTransaction } from "./utils/rpc";
43
- import { PoolConfig } from "./PoolConfig";
44
- import { checkIfAccountExists } from "./utils";
45
-
46
-
47
- /* USEAGE
48
-
49
- UI -----
50
- provider = from phatom
51
-
52
- client = new PerpetualsClient(provider, user.pubkey , programId);
53
-
54
- BOT cli --------
55
-
56
- provider = await getProvider(new DefaultWallet(DEFAULT_PERPS_USER));
57
-
58
- AnchorProvider.local(clusterUrl, {
59
- commitment: "confirmed",
60
- preflightCommitment: "confirmed",
61
- skipPreflight: true
62
- });
63
- process.env["ANCHOR_WALLET"] = adminKeyPath;
64
-
65
- client = new PerpetualsClient(provider, DEFAULT_PERPS_USER.pubkey , programId);
66
-
67
- */
68
-
69
- export type PerpClientOptions = {
70
- postSendTxCallback?: ({ txid }: { txid: string }) => void;
71
- prioritizationFee?: number;
72
- txConfirmationCommitment?: Commitment;
73
- };
74
-
75
- export class PerpetualsClient {
76
- provider: AnchorProvider;
77
- program: Program<Perpetuals>;
78
- admin: PublicKey;
79
- programId: PublicKey;
80
-
81
- // pdas
82
- multisig: { publicKey: PublicKey; bump: number };
83
- authority: { publicKey: PublicKey; bump: number };
84
- perpetuals: { publicKey: PublicKey; bump: number };
85
-
86
- private postSendTxCallback?: ({ txid }) => void;
87
- private prioritizationFee: number;
88
- private txConfirmationCommitment: Commitment;
89
-
90
- constructor(provider: AnchorProvider, programId: PublicKey, opts: PerpClientOptions) {
91
- // this.provider = AnchorProvider.local(clusterUrl, {
92
- // commitment: "confirmed",
93
- // preflightCommitment: "confirmed",
94
- // skipPreflight: true
95
- // });
96
- // setProvider(this.provider);
97
- this.provider = provider;
98
- setProvider(provider);
99
-
100
- // const idl = JSON.parse( fs.readFileSync("./target/idl/perpetuals.json", "utf8"));
101
- // const idl = JSON.parse(IDL);
102
- // const program = new anchor.Program(idl, programId, provider);
103
- this.program = new Program(IDL, programId);
104
- this.programId = programId;
105
- //this.program = workspace.Perpetuals as Program<Perpetuals>;
106
- // console.log("client constructor programID : ", this.program.programId.toBase58());
107
-
108
- // this.admin = Keypair.fromSecretKey(
109
- // new Uint8Array(JSON.parse(readFileSync(adminKey).toString()))
110
- // );
111
-
112
- this.admin = this.provider.wallet.publicKey;
113
- // console.log("admin:", this.admin.toBase58())
114
-
115
- this.multisig = this.findProgramAddress("multisig");
116
- this.authority = this.findProgramAddress("transfer_authority");
117
- this.perpetuals = this.findProgramAddress("perpetuals");
118
-
119
- this.prioritizationFee = opts?.prioritizationFee || 0;
120
- this.postSendTxCallback = opts?.postSendTxCallback;
121
- this.txConfirmationCommitment = opts?.txConfirmationCommitment ?? 'processed'
122
-
123
- BN.prototype.toJSON = function () {
124
- return this.toString(10);
125
- };
126
- }
127
-
128
- findProgramAddress = (label: string, extraSeeds: any = null) => {
129
- let seeds = [Buffer.from(utils.bytes.utf8.encode(label))];
130
- if (extraSeeds) {
131
- for (let extraSeed of extraSeeds) {
132
- if (typeof extraSeed === "string") {
133
- seeds.push(Buffer.from(utils.bytes.utf8.encode(extraSeed)));
134
- } else if (Array.isArray(extraSeed)) {
135
- seeds.push(Buffer.from(extraSeed));
136
- } else {
137
- seeds.push(extraSeed.toBuffer());
138
- }
139
- }
140
- }
141
- let res = PublicKey.findProgramAddressSync(seeds, this.program.programId);
142
- return { publicKey: res[0], bump: res[1] };
143
- };
144
-
145
- adjustTokenRatios = (ratios: TokenRatios[]) => {
146
- if (ratios.length == 0) {
147
- return ratios;
148
- }
149
- let target = Math.floor(10000 / ratios.length);
150
-
151
- for (let ratio of ratios) {
152
- ratio.target = new BN(target);
153
- }
154
-
155
- if (10000 % ratios.length !== 0) {
156
- ratios[ratios.length - 1].target = new BN(
157
- target + (10000 % ratios.length)
158
- );
159
- }
160
-
161
- return ratios;
162
- };
163
-
164
- getPerpetuals = async () => {
165
- return this.program.account.perpetuals.fetch(this.perpetuals.publicKey);
166
- };
167
-
168
- getPoolKey = (name: string) => {
169
- return this.findProgramAddress("pool", name).publicKey;
170
- };
171
-
172
- getPool = async (name: string) => {
173
- // console.log("pool:", this.getPoolKey(name).toBase58())
174
- return this.program.account.pool.fetch(this.getPoolKey(name));
175
- };
176
-
177
- getPools = async () => {
178
- //return this.program.account.pool.all();
179
- let perpetuals = await this.getPerpetuals();
180
- return this.program.account.pool.fetchMultiple(perpetuals.pools);
181
- };
182
-
183
- getPoolLpTokenKey = (name: string) => {
184
- return this.findProgramAddress("lp_token_mint", [this.getPoolKey(name)])
185
- .publicKey;
186
- };
187
-
188
- getCustodyKey = (poolName: string, tokenMint: PublicKey) => {
189
- return this.findProgramAddress("custody", [
190
- this.getPoolKey(poolName),
191
- tokenMint,
192
- ]).publicKey;
193
- };
194
-
195
- getCustodyTokenAccountKey = (poolName: string, tokenMint: PublicKey) => {
196
- return this.findProgramAddress("custody_token_account", [
197
- this.getPoolKey(poolName),
198
- tokenMint,
199
- ]).publicKey;
200
- };
201
-
202
- getCustodyOracleAccountKey = async (
203
- poolName: string,
204
- tokenMint: PublicKey
205
- ) => {
206
- return (await this.getCustody(poolName, tokenMint)).oracle.oracleAccount;
207
- };
208
-
209
- getCustodyTestOracleAccountKey = (poolName: string, tokenMint: PublicKey) => {
210
- return this.findProgramAddress("oracle_account", [
211
- this.getPoolKey(poolName),
212
- tokenMint,
213
- ]).publicKey;
214
- };
215
-
216
- getCustody = async (poolName: string, tokenMint: PublicKey) => {
217
- // console.log("custody key :", this.getCustodyKey(poolName, tokenMint).toBase58());
218
- return this.program.account.custody.fetch(
219
- this.getCustodyKey(poolName, tokenMint)
220
- );
221
- };
222
-
223
- getCustodies = async (poolName: string) => {
224
- //return this.program.account.custody.all();
225
- let pool = await this.getPool(poolName);
226
- return this.program.account.custody.fetchMultiple(
227
- pool.custodies
228
- );
229
- };
230
-
231
- getCustodyMetas = async (poolName: string) => {
232
- let pool = await this.getPool(poolName);
233
- let custodies: any = await this.program.account.custody.fetchMultiple(
234
- pool.custodies
235
- );
236
- let custodyMetas = [];
237
- for (const custody of pool.custodies) {
238
- custodyMetas.push({
239
- isSigner: false,
240
- isWritable: false,
241
- pubkey: custody,
242
- });
243
- }
244
- for (const custody of custodies) {
245
- custodyMetas.push({
246
- isSigner: false,
247
- isWritable: false,
248
- pubkey: custody?.oracle.oracleAccount,
249
- });
250
- }
251
- return custodyMetas;
252
- };
253
-
254
- getMultisig = async () => {
255
- return this.program.account.multisig.fetch(this.multisig.publicKey);
256
- };
257
-
258
- getPositionKey = (
259
- wallet: PublicKey,
260
- poolName: string,
261
- tokenMint: PublicKey,
262
- side: PositionSide
263
- ) => {
264
- let pool = this.getPoolKey(poolName);
265
- let custody = this.getCustodyKey(poolName, tokenMint);
266
- return this.findProgramAddress("position", [
267
- wallet,
268
- pool,
269
- custody,
270
- side === "long" ? [1] : [2],
271
- ]).publicKey;
272
- };
273
-
274
- getPosition = async (postionKey: PublicKey) => {
275
- return this.program.account.position.fetch(postionKey);
276
- };
277
-
278
- getUserPosition = async (
279
- wallet: PublicKey,
280
- poolName: string,
281
- tokenMint: PublicKey,
282
- side: PositionSide
283
- ) => {
284
- return this.program.account.position.fetch(
285
- this.getPositionKey(wallet, poolName, tokenMint, side)
286
- );
287
- };
288
-
289
- getUserPositions = async (
290
- wallet: PublicKey,
291
- poolConfig: PoolConfig
292
- ) => {
293
-
294
- const positionKeys = [
295
- ...poolConfig.getNonStableTokens().map(mint => this.getPositionKey(wallet, poolConfig.poolName, mint, 'long')),
296
- ...poolConfig.getNonStableTokens().map(mint => this.getPositionKey(wallet, poolConfig.poolName, mint, 'short')),
297
- ]
298
-
299
- let positionsDatas = (await this.provider.connection.getMultipleAccountsInfo(positionKeys)) ?? [];
300
-
301
- type Position = Awaited<ReturnType<typeof this.program.account.position.fetch>>
302
-
303
- return positionsDatas
304
- .map((p, i) => ({ pubkey: positionKeys[i], data: p }))
305
- .filter(f => f.data !== null)
306
- .map(k => ({ pubkey: k.pubkey, ...this.program.account.position.coder.accounts.decode<Position>('position', k.data!.data) }))
307
- };
308
-
309
- getPoolTokenPositions = async (poolName: string, tokenMint: PublicKey) => {
310
- let poolKey = this.getPoolKey(poolName);
311
- let custodyKey = this.getCustodyKey(poolName, tokenMint);
312
- let data = encode(
313
- Buffer.concat([poolKey.toBuffer(), custodyKey.toBuffer()])
314
- );
315
- let positions = await this.provider.connection.getProgramAccounts(
316
- this.program.programId,
317
- {
318
- filters: [{ dataSize: 200 }, { memcmp: { bytes: data, offset: 40 } }],
319
- }
320
- );
321
- return Promise.all(
322
- positions.map((position) => {
323
- return this.program.account.position.fetch(position.pubkey);
324
- })
325
- );
326
- };
327
-
328
- getAllPositions = async () => {
329
- return this.program.account.position.all();
330
- };
331
-
332
- getAccountDiscriminator = (name: string) => {
333
- return Buffer.from(sha256.digest(`account:${name}`)).slice(0, 8);
334
- };
335
-
336
-
337
- log = (...message: string[]) => {
338
- let date = new Date();
339
- let date_str = date.toDateString();
340
- let time = date.toLocaleTimeString();
341
- console.log(`[${date_str} ${time}] ${message}`);
342
- };
343
-
344
- prettyPrint = (object: object) => {
345
- console.log(JSON.stringify(object, null, 2));
346
- };
347
-
348
- ///////
349
- // instructions
350
-
351
- init = async (admins: PublicKey[], config: any) => {
352
- let perpetualsProgramData = PublicKey.findProgramAddressSync(
353
- [this.program.programId.toBuffer()],
354
- new PublicKey("BPFLoaderUpgradeab1e11111111111111111111111")
355
- )[0];
356
-
357
- let adminMetas = [];
358
- for (const admin of admins) {
359
- adminMetas.push({
360
- isSigner: false,
361
- isWritable: false,
362
- pubkey: admin,
363
- });
364
- }
365
-
366
- await this.program.methods
367
- .init(config)
368
- .accounts({
369
- upgradeAuthority: this.provider.wallet.publicKey,
370
- multisig: this.multisig.publicKey,
371
- transferAuthority: this.authority.publicKey,
372
- perpetuals: this.perpetuals.publicKey,
373
- perpetualsProgram: this.program.programId,
374
- perpetualsProgramData,
375
- systemProgram: SystemProgram.programId,
376
- tokenProgram: TOKEN_PROGRAM_ID,
377
- })
378
- .remainingAccounts(adminMetas)
379
- .rpc()
380
- .catch((err) => {
381
- console.error(err);
382
- throw err;
383
- });
384
- };
385
-
386
- setAdminSigners = async (admins: PublicKey[], minSignatures: number) => {
387
- let adminMetas = [];
388
- for (const admin of admins) {
389
- adminMetas.push({
390
- isSigner: false,
391
- isWritable: false,
392
- pubkey: admin,
393
- });
394
- }
395
- try {
396
- await this.program.methods
397
- .setAdminSigners({
398
- minSignatures,
399
- })
400
- .accounts({
401
- admin: this.admin,
402
- multisig: this.multisig.publicKey,
403
- })
404
- .remainingAccounts(adminMetas)
405
- // .signers([this.admin])
406
- .rpc();
407
- } catch (err) {
408
- // @ts-ignore
409
- if (this.printErrors) {
410
- console.error("setAdminSigners err:",err);
411
- }
412
- throw err;
413
- }
414
- };
415
-
416
- addPool = async (name: string) => {
417
- await this.program.methods
418
- .addPool({ name })
419
- .accounts({
420
- admin: this.provider.wallet.publicKey,
421
- multisig: this.multisig.publicKey,
422
- transferAuthority: this.authority.publicKey,
423
- perpetuals: this.perpetuals.publicKey,
424
- pool: this.getPoolKey(name),
425
- lpTokenMint: this.getPoolLpTokenKey(name),
426
- systemProgram: SystemProgram.programId,
427
- tokenProgram: TOKEN_PROGRAM_ID,
428
- rent: SYSVAR_RENT_PUBKEY,
429
- })
430
- // .signers([this.admin])
431
- .rpc()
432
- .catch((err) => {
433
- console.error(err);
434
- throw err;
435
- });
436
- };
437
-
438
- removePool = async (name: string) => {
439
- await this.program.methods
440
- .removePool({})
441
- .accounts({
442
- admin: this.admin,
443
- multisig: this.multisig.publicKey,
444
- transferAuthority: this.authority.publicKey,
445
- perpetuals: this.perpetuals.publicKey,
446
- pool: this.getPoolKey(name),
447
- systemProgram: SystemProgram.programId,
448
- })
449
- // .signers([this.admin])
450
- .rpc()
451
- .catch((err) => {
452
- console.error(err);
453
- throw err;
454
- });
455
- };
456
-
457
- addCustody = async (
458
- poolName: string,
459
- tokenMint: PublicKey,
460
- isStable: boolean,
461
- oracle: OracleParams,
462
- pricing: PricingParams,
463
- permissions: Permissions,
464
- fees: Fees,
465
- borrowRate: BorrowRateParams,
466
- ratios: TokenRatios[]
467
- ) => {
468
- // console.log("CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
469
- // console.log("getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
470
- try {
471
- const trx_id = await this.program.methods
472
- // @ts-ignore
473
- .addCustody({
474
- isStable,
475
- oracle,
476
- pricing,
477
- permissions,
478
- fees,
479
- borrowRate,
480
- ratios,
481
- })
482
- .accounts({
483
- admin: this.admin,
484
- multisig: this.multisig.publicKey,
485
- transferAuthority: this.authority.publicKey,
486
- perpetuals: this.perpetuals.publicKey,
487
- pool: this.getPoolKey(poolName),
488
- custody: this.getCustodyKey(poolName, tokenMint),
489
- custodyTokenAccount: this.getCustodyTokenAccountKey(
490
- poolName,
491
- tokenMint
492
- ),
493
- custodyTokenMint: tokenMint,
494
- systemProgram: SystemProgram.programId,
495
- tokenProgram: TOKEN_PROGRAM_ID,
496
- rent: SYSVAR_RENT_PUBKEY,
497
- })
498
- // .signers([this.admin])
499
- .rpc()
500
- .catch((err) => {
501
- console.error(err);
502
- throw err;
503
- });
504
-
505
- console.log("trx_id:", `https://explorer.solana.com/tx/${trx_id}?cluster=devnet`)
506
- } catch (error) {
507
- console.error("cli error :", error);
508
- }
509
-
510
-
511
- };
512
-
513
- editCustody = async (
514
- poolName: string,
515
- tokenMint: PublicKey,
516
- isStable: boolean,
517
- oracle: OracleParams,
518
- pricing: PricingParams,
519
- permissions: Permissions,
520
- fees: Fees,
521
- borrowRate: BorrowRateParams,
522
- ratios: TokenRatios[]
523
- ) => {
524
- // console.log("editCustody CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
525
- // console.log("editCustody getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
526
-
527
- const trx_id = await this.program.methods
528
- //@ts-ignore
529
- .testingEditCustody({
530
- isStable,
531
- oracle,
532
- pricing,
533
- permissions,
534
- fees,
535
- borrowRate,
536
- ratios,
537
- })
538
- .accounts({
539
- admin: this.admin,
540
- multisig: this.multisig.publicKey,
541
- transferAuthority: this.authority.publicKey,
542
- perpetuals: this.perpetuals.publicKey,
543
- pool: this.getPoolKey(poolName),
544
- custody: this.getCustodyKey(poolName, tokenMint),
545
- custodyTokenAccount: this.getCustodyTokenAccountKey(
546
- poolName,
547
- tokenMint
548
- ),
549
- custodyTokenMint: tokenMint,
550
- systemProgram: SystemProgram.programId,
551
- tokenProgram: TOKEN_PROGRAM_ID,
552
- rent: SYSVAR_RENT_PUBKEY,
553
- })
554
- // .signers([this.admin])
555
- .rpc()
556
- .catch((err) => {
557
- console.error(err);
558
- throw err;
559
- });
560
- console.log("trx_id:", `https://explorer.solana.com/tx/${trx_id}?cluster=devnet`)
561
- };
562
-
563
- removeCustody = async (poolName: string, tokenMint: PublicKey, ratios: TokenRatios[]) => {
564
- await this.program.methods
565
- .removeCustody({ ratios })
566
- .accounts({
567
- admin: this.admin,
568
- multisig: this.multisig.publicKey,
569
- transferAuthority: this.authority.publicKey,
570
- perpetuals: this.perpetuals.publicKey,
571
- pool: this.getPoolKey(poolName),
572
- custody: this.getCustodyKey(poolName, tokenMint),
573
- custodyTokenAccount: this.getCustodyTokenAccountKey(
574
- poolName,
575
- tokenMint
576
- ),
577
- systemProgram: SystemProgram.programId,
578
- tokenProgram: TOKEN_PROGRAM_ID,
579
- })
580
- // .signers([this.admin])
581
- .rpc()
582
- .catch((err) => {
583
- console.error(err);
584
- throw err;
585
- });
586
- };
587
-
588
- upgradeCustody = async (poolName: string, tokenMint: PublicKey) => {
589
- await this.program.methods
590
- .upgradeCustody({})
591
- .accounts({
592
- admin: this.admin,
593
- multisig: this.multisig.publicKey,
594
- pool: this.getPoolKey(poolName),
595
- custody: this.getCustodyKey(poolName, tokenMint),
596
- systemProgram: SystemProgram.programId,
597
- })
598
- // .signers([this.admin])
599
- .rpc()
600
- .catch((err) => {
601
- console.error(err);
602
- throw err;
603
- });
604
- };
605
-
606
- liquidate = async (
607
- wallet: PublicKey,
608
- poolName: string,
609
- tokenMint: PublicKey,
610
- side: PositionSide,
611
- receivingAccount: PublicKey,
612
- rewardsReceivingAccount: PublicKey
613
- ) => {
614
- return await this.program.methods
615
- .liquidate({})
616
- .accounts({
617
- signer: this.provider.wallet.publicKey,
618
- receivingAccount,
619
- rewardsReceivingAccount,
620
- transferAuthority: this.authority.publicKey,
621
- perpetuals: this.perpetuals.publicKey,
622
- pool: this.getPoolKey(poolName),
623
- position: this.getPositionKey(wallet, poolName, tokenMint, side),
624
- custody: this.getCustodyKey(poolName, tokenMint),
625
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
626
- poolName,
627
- tokenMint
628
- ),
629
- custodyTokenAccount: this.getCustodyTokenAccountKey(
630
- poolName,
631
- tokenMint
632
- ),
633
- tokenProgram: TOKEN_PROGRAM_ID,
634
- })
635
- .rpc()
636
- .catch((err) => {
637
- console.error(err);
638
- throw err;
639
- });
640
- };
641
-
642
- getOraclePrice = async (
643
- poolName: string,
644
- tokenMint: PublicKey,
645
- ema: boolean
646
- ) => {
647
- return await this.program.methods
648
- .getOraclePrice({
649
- ema,
650
- })
651
- .accounts({
652
- // signer: this.provider.wallet.publicKey,
653
- perpetuals: this.perpetuals.publicKey,
654
- pool: this.getPoolKey(poolName),
655
- custody: this.getCustodyKey(poolName, tokenMint),
656
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
657
- poolName,
658
- tokenMint
659
- ),
660
- })
661
- .view()
662
- .catch((err) => {
663
- console.error(err);
664
- throw err;
665
- });
666
- };
667
-
668
- getAddLiquidityAmountAndFee = async (
669
- poolName: string,
670
- tokenMint: PublicKey,
671
- amount: BN
672
- ) => {
673
- return await this.program.methods
674
- .getAddLiquidityAmountAndFee({
675
- amountIn: amount,
676
- })
677
- .accounts({
678
- perpetuals: this.perpetuals.publicKey,
679
- pool: this.getPoolKey(poolName),
680
- custody: this.getCustodyKey(poolName, tokenMint),
681
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
682
- poolName,
683
- tokenMint
684
- ),
685
- lpTokenMint: this.getPoolLpTokenKey(poolName),
686
- })
687
- .remainingAccounts(await this.getCustodyMetas(poolName))
688
- .view()
689
- .catch((err) => {
690
- console.error(err);
691
- throw err;
692
- });
693
- };
694
-
695
- getRemoveLiquidityAmountAndFee = async (
696
- poolName: string,
697
- tokenMint: PublicKey,
698
- lpAmount: BN
699
- ) => {
700
- return await this.program.methods
701
- .getRemoveLiquidityAmountAndFee({
702
- lpAmountIn: lpAmount,
703
- })
704
- .accounts({
705
- perpetuals: this.perpetuals.publicKey,
706
- pool: this.getPoolKey(poolName),
707
- custody: this.getCustodyKey(poolName, tokenMint),
708
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
709
- poolName,
710
- tokenMint
711
- ),
712
- lpTokenMint: this.getPoolLpTokenKey(poolName),
713
- })
714
- .remainingAccounts(await this.getCustodyMetas(poolName))
715
- .view()
716
- .catch((err) => {
717
- console.error(err);
718
- throw err;
719
- });
720
- };
721
-
722
- getEntryPriceAndFee = async (
723
- poolName: string,
724
- tokenMint: PublicKey,
725
- collateral: BN,
726
- size: BN,
727
- side: PositionSide
728
- ) => {
729
- // console.log("perps: ", this.perpetuals.publicKey.toBase58())
730
- // console.log("poolKey: ", this.getPoolKey(poolName).toBase58())
731
- // console.log("custody key : ", this.getCustodyKey(poolName, tokenMint).toBase58());
732
- // console.log("oracle: ", (await this.getCustodyOracleAccountKey(poolName, tokenMint)).toBase58())
733
-
734
- //@ts-ignore
735
- return await this.program.methods
736
- //@ts-ignore
737
- .getEntryPriceAndFee({
738
- collateral,
739
- size,
740
- side: side == "long" ? { long: {} } : { short: {} },
741
- })
742
- .accounts({
743
- // signer: this.provider.wallet.publicKey,
744
- perpetuals: this.perpetuals.publicKey,
745
- pool: this.getPoolKey(poolName),
746
- custody: this.getCustodyKey(poolName, tokenMint),
747
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
748
- poolName,
749
- tokenMint
750
- ),
751
- // lockCustody: this.getCustodyKey(poolName, tokenMint),
752
- // lockCustodyOracleAccount: await this.getCustodyOracleAccountKey(
753
- // poolName,
754
- // tokenMint
755
- // ),
756
- })
757
- .view()
758
- .catch((err) => {
759
- console.error(err);
760
- throw err;
761
- });
762
- };
763
-
764
- getExitPriceAndFee = async (
765
- wallet: PublicKey,
766
- poolName: string,
767
- tokenMint: PublicKey,
768
- side: PositionSide
769
- ) => {
770
- return await this.program.methods
771
- .getExitPriceAndFee({})
772
- .accounts({
773
- perpetuals: this.perpetuals.publicKey,
774
- pool: this.getPoolKey(poolName),
775
- position: this.getPositionKey(wallet, poolName, tokenMint, side),
776
- custody: this.getCustodyKey(poolName, tokenMint),
777
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
778
- poolName,
779
- tokenMint
780
- ),
781
- })
782
- .view()
783
- .catch((err) => {
784
- console.error(err);
785
- throw err;
786
- });
787
- };
788
-
789
- getLiquidationPriceView = async (
790
- wallet: PublicKey,
791
- poolName: string,
792
- tokenMint: PublicKey,
793
- side: PositionSide,
794
- addCollateral = new BN(0),
795
- removeCollateral = new BN(0)
796
- ) => {
797
- return await this.program.methods
798
- .getLiquidationPrice({
799
- addCollateral,
800
- removeCollateral,
801
- })
802
- .accounts({
803
- perpetuals: this.perpetuals.publicKey,
804
- pool: this.getPoolKey(poolName),
805
- position: this.getPositionKey(wallet, poolName, tokenMint, side),
806
- custody: this.getCustodyKey(poolName, tokenMint),
807
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
808
- poolName,
809
- tokenMint
810
- ),
811
- })
812
- .view()
813
- .catch((err) => {
814
- console.error(err);
815
- throw err;
816
- });
817
- };
818
-
819
- getLiquidationPriceTrx = async (
820
- wallet: PublicKey,
821
- poolName: string,
822
- tokenMint: PublicKey,
823
- side: PositionSide,
824
- addCollateral = new BN(0),
825
- removeCollateral = new BN(0)
826
- ) => {
827
- return await this.program.methods
828
- .getLiquidationPrice({
829
- addCollateral,
830
- removeCollateral,
831
- })
832
- .accounts({
833
- perpetuals: this.perpetuals.publicKey,
834
- pool: this.getPoolKey(poolName),
835
- position: this.getPositionKey(wallet, poolName, tokenMint, side),
836
- custody: this.getCustodyKey(poolName, tokenMint),
837
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
838
- poolName,
839
- tokenMint
840
- ),
841
- })
842
- .rpc()
843
- .catch((err) => {
844
- console.error(err);
845
- throw err;
846
- });
847
- };
848
-
849
- // TODO: currently just static, need to write
850
- getLiquidationPrice = (
851
- postionKey: PublicKey,
852
- postionData: Position,
853
- tokenPrice: OraclePrice,
854
- tokenEmaPrice: OraclePrice,
855
- custodyAccount: CustodyAccount,
856
- poolAccount: PoolAccount,
857
- currentTime: BN,
858
- addCollateral = new BN(0),
859
- removeCollateral = new BN(0)
860
- ) => {
861
- // const positionAccount = PositionAccount.from(postionKey, postionData);
862
- let x : BN;
863
- if (isVariant(postionData.side, 'long')) {
864
- x = tokenPrice.price.mul(new BN(90)).div(new BN(90))
865
- } else {
866
- x = tokenPrice.price.mul(new BN(100)).div(new BN(90))
867
- }
868
- return new OraclePrice({price: x ,exponent : tokenPrice.exponent})
869
- };
870
-
871
- getLiquidationState = async (
872
- wallet: PublicKey,
873
- poolName: string,
874
- tokenMint: PublicKey,
875
- side: PositionSide
876
- ) => {
877
- return await this.program.methods
878
- .getLiquidationState({})
879
- .accounts({
880
- perpetuals: this.perpetuals.publicKey,
881
- pool: this.getPoolKey(poolName),
882
- position: this.getPositionKey(wallet, poolName, tokenMint, side),
883
- custody: this.getCustodyKey(poolName, tokenMint),
884
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
885
- poolName,
886
- tokenMint
887
- ),
888
- })
889
- .view()
890
- .catch((err) => {
891
- console.error(err);
892
- throw err;
893
- });
894
- };
895
-
896
- getPnlView = async (
897
- wallet: PublicKey,
898
- poolName: string,
899
- tokenMint: PublicKey,
900
- side: PositionSide
901
- ) => {
902
- const pos = this.getPositionKey(wallet, poolName, tokenMint, side);
903
- // console.log("pos:", pos.toBase58())
904
- return await this.program.methods
905
- .getPnl({})
906
- .accounts({
907
- perpetuals: this.perpetuals.publicKey,
908
- pool: this.getPoolKey(poolName),
909
- position: pos,
910
- custody: this.getCustodyKey(poolName, tokenMint),
911
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
912
- poolName,
913
- tokenMint
914
- ),
915
- })
916
- .view()
917
- .catch((err) => {
918
- console.error(err);
919
- throw err;
920
- });
921
- };
922
-
923
-
924
- getPnlTrx = async (
925
- wallet: PublicKey,
926
- poolName: string,
927
- tokenMint: PublicKey,
928
- side: PositionSide
929
- ) => {
930
- const pos = this.getPositionKey(wallet, poolName, tokenMint, side);
931
- // console.log("pos:", pos.toBase58())
932
- return await this.program.methods
933
- .getPnl({})
934
- .accounts({
935
- perpetuals: this.perpetuals.publicKey,
936
- pool: this.getPoolKey(poolName),
937
- position: pos,
938
- custody: this.getCustodyKey(poolName, tokenMint),
939
- custodyOracleAccount: await this.getCustodyOracleAccountKey(
940
- poolName,
941
- tokenMint
942
- ),
943
- })
944
- .rpc()
945
- .catch((err) => {
946
- console.error(err);
947
- throw err;
948
- });
949
- };
950
-
951
-
952
- getPnl = (
953
- postionKey: PublicKey,
954
- postionData: Position,
955
- tokenPrice: OraclePrice,
956
- tokenEmaPrice: OraclePrice,
957
- custodyAccount: CustodyAccount,
958
- poolAccount: PoolAccount,
959
- currentTime: BN
960
- ) => {
961
-
962
- const positionAccount = PositionAccount.from(postionKey, postionData);
963
- // console.log("positionAccount:",positionAccount);
964
- // console.log("side :", postionData.side, (isVariant(postionData.side, 'long')))
965
-
966
- let { profit, loss, exitFee } = poolAccount.getPnlUsd(
967
- positionAccount,
968
- tokenPrice,
969
- tokenEmaPrice,
970
- custodyAccount,
971
- currentTime,
972
- false,
973
- );
974
-
975
- return {
976
- profit,
977
- loss
978
- }
979
-
980
- }
981
-
982
- getSwapAmountAndFees = async (
983
- poolName: string,
984
- tokenMintIn: PublicKey,
985
- tokenMintOut: PublicKey,
986
- amountIn: BN
987
- ) => {
988
- return await this.program.methods
989
- .getSwapAmountAndFees({
990
- amountIn,
991
- })
992
- .accounts({
993
- perpetuals: this.perpetuals.publicKey,
994
- pool: this.getPoolKey(poolName),
995
- receivingCustody: this.getCustodyKey(poolName, tokenMintIn),
996
- receivingCustodyOracleAccount: await this.getCustodyOracleAccountKey(
997
- poolName,
998
- tokenMintIn
999
- ),
1000
- dispensingCustody: this.getCustodyKey(poolName, tokenMintOut),
1001
- dispensingCustodyOracleAccount: await this.getCustodyOracleAccountKey(
1002
- poolName,
1003
- tokenMintOut
1004
- ),
1005
- })
1006
- .view()
1007
- .catch((err) => {
1008
- console.error(err);
1009
- throw err;
1010
- });
1011
- };
1012
-
1013
- getAumView = async (poolName: string) => {
1014
- return await this.program.methods
1015
- .getAssetsUnderManagement({})
1016
- .accounts({
1017
- perpetuals: this.perpetuals.publicKey,
1018
- pool: this.getPoolKey(poolName),
1019
- })
1020
- .remainingAccounts(await this.getCustodyMetas(poolName))
1021
- .view()
1022
- .catch((err) => {
1023
- console.error(err);
1024
- throw err;
1025
- });
1026
- };
1027
-
1028
- getAumTrx = async (poolName: string) => {
1029
- return await this.program.methods
1030
- .getAssetsUnderManagement({})
1031
- .accounts({
1032
- perpetuals: this.perpetuals.publicKey,
1033
- pool: this.getPoolKey(poolName),
1034
- })
1035
- .remainingAccounts(await this.getCustodyMetas(poolName))
1036
- .rpc()
1037
- .catch((err) => {
1038
- console.error(err);
1039
- throw err;
1040
- });
1041
- };
1042
-
1043
- getAumSdk = (
1044
- poolAccount: PoolAccount,
1045
- token_prices: OraclePrice[],
1046
- token_ema_prices: OraclePrice[],
1047
- custodies: CustodyAccount[],
1048
- aum_calc_mode: AumCalcMode,
1049
- currentTime: BN
1050
- ) => {
1051
- // console.log("poolAccount:",poolAccount);
1052
-
1053
- return poolAccount.getAssetsUnderManagementUsd(
1054
- token_prices,
1055
- token_ema_prices,
1056
- custodies,
1057
- aum_calc_mode,
1058
- currentTime
1059
- );
1060
- };
1061
-
1062
- // TODO: handle SOL wrapping to WSOL and create a ATA - DONE
1063
- // TODO: Balance checks - DONE
1064
- // TODO: ATA check - else create - DONE
1065
- // Create WSOL Token account and not ATA and close it in end
1066
- // TODO: close other Accounts - NOT NEEDED
1067
- openPosition = async (
1068
- payTokenSymbol: string,
1069
- priceAfterSlippage: BN,
1070
- collateralWithfee: BN,
1071
- fee : BN,
1072
- size: BN,
1073
- side: Side,
1074
- poolConfig: PoolConfig,
1075
- createUserWSOLATA = true,
1076
- skipBalanceChecks = false
1077
- ): Promise< { instructions : TransactionInstruction[] , additionalSigners: Signer[]} > => {
1078
-
1079
- console.log("open position :::", payTokenSymbol, poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey.toBase58());
1080
-
1081
- // const slippageMultiplier = isVariant(side, 'long') ? -1 : 1;
1082
- // const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
1083
-
1084
- let publicKey = this.provider.wallet.publicKey;
1085
- const payTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey))!;
1086
-
1087
- let userCustodyTokenAccount = await getAssociatedTokenAddress(
1088
- poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey,
1089
- publicKey
1090
- );
1091
-
1092
- let wrappedSolAccount: Keypair | undefined;
1093
- let preInstructions: TransactionInstruction[] = [];
1094
- let instructions: TransactionInstruction[] = [];
1095
- let postInstructions: TransactionInstruction[] = [];
1096
- const additionalSigners: Signer[] = [];
1097
-
1098
- try {
1099
-
1100
- // https://github.com/blockworks-foundation/mango-v4/blob/1ba6513b5ea2b0e557808e712fcf0a811968b45b/ts/client/src/client.ts#L1252
1101
- // Create WSOL Token account and not ATA and close it in end
1102
- if (payTokenSymbol == 'SOL' && createUserWSOLATA) {
1103
- console.log("payTokenSymbol === sol", payTokenSymbol);
1104
- wrappedSolAccount = new Keypair();
1105
- const accCreationLamports = (await getMinimumBalanceForRentExemptAccount(this.provider.connection)); // for account creation
1106
- console.log("accCreationLamports:",accCreationLamports)
1107
- const lamports = collateralWithfee.add(new BN(accCreationLamports)); // for account creation
1108
-
1109
- preInstructions = [
1110
- SystemProgram.createAccount({
1111
- fromPubkey: publicKey,
1112
- newAccountPubkey: wrappedSolAccount.publicKey,
1113
- lamports: lamports.toNumber(), //will this break for large amounts ??
1114
- space: 165,
1115
- programId: TOKEN_PROGRAM_ID,
1116
- }),
1117
- createInitializeAccount3Instruction(
1118
- wrappedSolAccount.publicKey,
1119
- NATIVE_MINT,
1120
- publicKey,
1121
- ),
1122
- ];
1123
- postInstructions = [
1124
- createCloseAccountInstruction(
1125
- wrappedSolAccount.publicKey,
1126
- publicKey,
1127
- publicKey,
1128
- ),
1129
- ];
1130
- additionalSigners.push(wrappedSolAccount);
1131
-
1132
- } else if(createUserWSOLATA == false){
1133
- console.log("skip WSOL checks and creation ,since createUserWSOLATA == false")
1134
- } else {
1135
- // for other tokens check if ATA and balance
1136
- if (!(await checkIfAccountExists(userCustodyTokenAccount, this.provider.connection))) {
1137
- throw "Insufficient Funds , token Account doesn't exist"
1138
- }
1139
-
1140
- if(!skipBalanceChecks){
1141
- const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(userCustodyTokenAccount)).value.amount);
1142
- if (tokenAccountBalance.lt(collateralWithfee)) {
1143
- throw `Insufficient Funds need more ${collateralWithfee.sub(tokenAccountBalance)} tokens`
1144
- }
1145
- }
1146
-
1147
- }
1148
-
1149
- // replace with getPositionKey()
1150
- let positionAccount = PublicKey.findProgramAddressSync(
1151
- [
1152
- Buffer.from("position"),
1153
- publicKey.toBuffer(),
1154
- poolConfig.poolAddress.toBuffer(),
1155
- payTokenCustody.custodyAccount.toBuffer(),
1156
- isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
1157
- ],
1158
- this.programId
1159
- )[0];
1160
-
1161
- const params: any = {
1162
- price: priceAfterSlippage,
1163
- collateral : collateralWithfee,
1164
- size,
1165
- side,
1166
- };
1167
-
1168
- let instruction = await this.program.methods
1169
- .openPosition(params)
1170
- .accounts({
1171
- owner: publicKey,
1172
- fundingAccount: payTokenSymbol == 'SOL' ? wrappedSolAccount.publicKey : userCustodyTokenAccount,
1173
- transferAuthority: poolConfig.transferAuthority,
1174
- perpetuals: poolConfig.perpetuals,
1175
- pool: poolConfig.poolAddress,
1176
- position: positionAccount,
1177
- custody: payTokenCustody.custodyAccount,
1178
- custodyOracleAccount:
1179
- payTokenCustody.oracleAddress,
1180
- custodyTokenAccount:
1181
- payTokenCustody.tokenAccount,
1182
- systemProgram: SystemProgram.programId,
1183
- tokenProgram: TOKEN_PROGRAM_ID,
1184
- }).instruction()
1185
-
1186
-
1187
- instructions.push(instruction);
1188
-
1189
- } catch (error) {
1190
- console.log("perpClient openPosition error:", error)
1191
- }
1192
- return {
1193
- instructions : [...preInstructions, ...instructions ,...postInstructions],
1194
- additionalSigners
1195
- };
1196
- }
1197
-
1198
- // TODO: handle SOL wrapping to WSOL and create a ATA - NOT NEEDED
1199
- // TODO : Balance checks - NOT NEEDED
1200
- // TODO: ATA check - else create - DONE
1201
- // TODO: for close Accounts - DONE BY ANCHOR
1202
- // TODO : if out token WSOL -> unwrap to SOL - DONE
1203
- closePosition = async (
1204
- receivingTokenSymbol: string,
1205
- priceAfterSlippage: BN,
1206
- side: Side,
1207
- poolConfig: PoolConfig,
1208
- createUserATA = true,
1209
- closeUsersWSOLATA = false // to get back WSOL=>SOL
1210
- ): Promise< { instructions : TransactionInstruction[] , additionalSigners: Signer[]}> => {
1211
-
1212
- console.log("close position :::", receivingTokenSymbol, poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey.toBase58());
1213
-
1214
- // opp during close
1215
- // const slippageMultiplier = isVariant(side, 'short') ? -1 : 1;
1216
- // const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
1217
-
1218
- let publicKey = this.provider.wallet.publicKey;
1219
-
1220
- let userReceivingTokenAccount : PublicKey;
1221
- let wrappedSolAccount: Keypair | undefined;
1222
- let preInstructions: TransactionInstruction[] = [];
1223
- let instructions: TransactionInstruction[] = [];
1224
- let postInstructions: TransactionInstruction[] = [];
1225
- const additionalSigners: Signer[] = [];
1226
- try {
1227
-
1228
- if (receivingTokenSymbol == 'SOL') {
1229
- wrappedSolAccount = new Keypair();
1230
- userReceivingTokenAccount = wrappedSolAccount.publicKey;
1231
- const lamports = (await getMinimumBalanceForRentExemptAccount(this.provider.connection)); // for account creation
1232
-
1233
- preInstructions = [
1234
- SystemProgram.createAccount({
1235
- fromPubkey: publicKey,
1236
- newAccountPubkey: wrappedSolAccount.publicKey,
1237
- lamports: lamports, //will this break for large amounts ??
1238
- space: 165,
1239
- programId: TOKEN_PROGRAM_ID,
1240
- }),
1241
- createInitializeAccount3Instruction(
1242
- wrappedSolAccount.publicKey,
1243
- NATIVE_MINT,
1244
- publicKey,
1245
- ),
1246
- ];
1247
- postInstructions = [
1248
- createCloseAccountInstruction(
1249
- wrappedSolAccount.publicKey,
1250
- publicKey,
1251
- publicKey,
1252
- ),
1253
- ];
1254
- additionalSigners.push(wrappedSolAccount);
1255
- } else {
1256
-
1257
- userReceivingTokenAccount = await getAssociatedTokenAddress(
1258
- poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey,
1259
- publicKey
1260
- );
1261
-
1262
- if (createUserATA && !(await checkIfAccountExists(userReceivingTokenAccount, this.provider.connection))) {
1263
- preInstructions.push(
1264
- createAssociatedTokenAccountInstruction(
1265
- publicKey,
1266
- userReceivingTokenAccount,
1267
- publicKey,
1268
- poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey
1269
- )
1270
- );
1271
- }
1272
-
1273
- }
1274
-
1275
-
1276
- const receivingTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey))!;
1277
-
1278
- // replace with getPositionKey
1279
- let positionAccount = PublicKey.findProgramAddressSync(
1280
- [
1281
- Buffer.from("position"),
1282
- publicKey.toBuffer(),
1283
- poolConfig.poolAddress.toBuffer(),
1284
- receivingTokenCustody.custodyAccount.toBuffer(),
1285
- isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
1286
- ],
1287
- this.programId
1288
- )[0];
1289
-
1290
- // console.log("positionAccount:", positionAccount.toBase58())
1291
- const params: any = {
1292
- price: priceAfterSlippage,
1293
- };
1294
-
1295
- let instruction = await this.program.methods
1296
- .closePosition(params)
1297
- .accounts({
1298
- owner: publicKey,
1299
- receivingAccount: userReceivingTokenAccount,
1300
- transferAuthority: poolConfig.transferAuthority,
1301
- perpetuals: poolConfig.perpetuals,
1302
- pool: poolConfig.poolAddress,
1303
- position: positionAccount,
1304
- custody: receivingTokenCustody.custodyAccount,
1305
- custodyOracleAccount:
1306
- receivingTokenCustody.oracleAddress,
1307
- custodyTokenAccount:
1308
- receivingTokenCustody.tokenAccount,
1309
- tokenProgram: TOKEN_PROGRAM_ID,
1310
- }).instruction();
1311
- instructions.push(instruction)
1312
-
1313
- if (receivingTokenSymbol == 'WSOL' && closeUsersWSOLATA) {
1314
- const closeWsolATAIns = createCloseAccountInstruction(userReceivingTokenAccount, publicKey, publicKey);
1315
- postInstructions.push(closeWsolATAIns);
1316
- }
1317
- } catch (error) {
1318
- console.error("perpclient closePosition error:", error);
1319
- }
1320
-
1321
- return {
1322
- instructions : [...preInstructions, ...instructions ,...postInstructions],
1323
- additionalSigners
1324
- };
1325
- }
1326
-
1327
-
1328
- // ==== OLD
1329
- // TODO: handle SOL wrapping to WSOL and create a ATA - DONE
1330
- // TODO: Balance checks - DONE
1331
- // TODO: ATA check - else create - DONE
1332
- // TODO: for close Accounts - NOT NEEDED
1333
- openPositionOld = async (
1334
- payTokenSymbol: string,
1335
- priceAfterSlippage: BN,
1336
- collateral: BN,
1337
- fee : BN,
1338
- size: BN,
1339
- side: Side,
1340
- poolConfig: PoolConfig,
1341
- createUserWSOLATA = true // if false will also skip balance checks
1342
- ): Promise<TransactionInstruction[]> => {
1343
-
1344
- console.log("open position :::", payTokenSymbol, poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey.toBase58());
1345
-
1346
- // const slippageMultiplier = isVariant(side, 'long') ? -1 : 1;
1347
- // const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
1348
-
1349
- let publicKey = this.provider.wallet.publicKey;
1350
- const payTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey))!;
1351
-
1352
- let userCustodyTokenAccount = await getAssociatedTokenAddress(
1353
- poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey,
1354
- publicKey
1355
- );
1356
-
1357
- const instructions = [];
1358
- try {
1359
-
1360
- if (payTokenSymbol == 'SOL' && createUserWSOLATA) {
1361
- console.log("payTokenSymbol === sol", payTokenSymbol);
1362
- const wsolAssociatedTokenAccount = userCustodyTokenAccount;
1363
- // await getAssociatedTokenAddress(
1364
- // NATIVE_MINT,
1365
- // publicKey
1366
- // );
1367
- const wsolATAExist = await checkIfAccountExists(wsolAssociatedTokenAccount, this.provider.connection)
1368
- if (!wsolATAExist) {
1369
- console.log("wsol ata does not exist");
1370
- instructions.push(
1371
- createAssociatedTokenAccountInstruction(
1372
- publicKey,
1373
- wsolAssociatedTokenAccount,
1374
- publicKey,
1375
- NATIVE_MINT
1376
- )
1377
- );
1378
- }
1379
-
1380
- const collateralWithfee = collateral.add(fee);
1381
-
1382
- // get balance of WSOL associated token account
1383
- const wsolBalance = new BN(wsolATAExist ? (await this.provider.connection.getTokenAccountBalance(wsolAssociatedTokenAccount)).value.amount : 0);
1384
- if (wsolBalance.lt(collateralWithfee)) {
1385
- console.log("WSOL balance insufficient \n so Convert SOL to WSOL");
1386
- let unWrappedSolBalance = new BN(await this.provider.connection.getBalance(publicKey));
1387
- const totalSolBal = unWrappedSolBalance.add(wsolBalance);
1388
- // const rentExemptSolNeedforATA = new BN(0.02 * LAMPORTS_PER_SOL);
1389
- // console.log("rentExemptSolNeedforATA:",rentExemptSolNeedforATA.toString())
1390
- //TODOD :: add(rentExemptSolNeedforATA)
1391
- if (totalSolBal.lt(collateralWithfee)) {
1392
- throw "Insufficient SOL Funds"
1393
- } else {
1394
- console.log("SOL balance sufficient so transfer from SOL to WSOL ATA")
1395
- }
1396
-
1397
- let conversionAmt = collateralWithfee.sub(wsolBalance);
1398
- console.log("conversionAmt:",conversionAmt.toString())
1399
- instructions.push(
1400
- SystemProgram.transfer({
1401
- fromPubkey: publicKey,
1402
- toPubkey: wsolAssociatedTokenAccount,
1403
- lamports: conversionAmt.toNumber(), // IS IT SAFE TO PUT AS NUMBER
1404
- }),
1405
- createSyncNativeInstruction(wsolAssociatedTokenAccount)
1406
- );
1407
- }
1408
- } else if(createUserWSOLATA == false){
1409
- console.log("skip WSOL checks and creation ,since createUserWSOLATA == false")
1410
- } else {
1411
- // for other tokens check if ATA and balance
1412
- if (!(await checkIfAccountExists(userCustodyTokenAccount, this.provider.connection))) {
1413
- throw "Insufficient Funds , token Account doesn't exist"
1414
- }
1415
- const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(userCustodyTokenAccount)).value.amount);
1416
- if (tokenAccountBalance.lt(collateral.add(fee))) {
1417
- throw "Insufficient Funds"
1418
- }
1419
- }
1420
-
1421
- // replace with getPositionKey()
1422
- let positionAccount = PublicKey.findProgramAddressSync(
1423
- [
1424
- Buffer.from("position"),
1425
- publicKey.toBuffer(),
1426
- poolConfig.poolAddress.toBuffer(),
1427
- payTokenCustody.custodyAccount.toBuffer(),
1428
- isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
1429
- ],
1430
- this.programId
1431
- )[0];
1432
-
1433
- const params: any = {
1434
- price: priceAfterSlippage,
1435
- collateral,
1436
- size,
1437
- side,
1438
- };
1439
-
1440
- let instruction = await this.program.methods
1441
- .openPosition(params)
1442
- .accounts({
1443
- owner: publicKey,
1444
- fundingAccount: userCustodyTokenAccount,
1445
- transferAuthority: poolConfig.transferAuthority,
1446
- perpetuals: poolConfig.perpetuals,
1447
- pool: poolConfig.poolAddress,
1448
- position: positionAccount,
1449
- custody: payTokenCustody.custodyAccount,
1450
- custodyOracleAccount:
1451
- payTokenCustody.oracleAddress,
1452
- custodyTokenAccount:
1453
- payTokenCustody.tokenAccount,
1454
- systemProgram: SystemProgram.programId,
1455
- tokenProgram: TOKEN_PROGRAM_ID,
1456
- }).instruction()
1457
- instructions.push(instruction);
1458
-
1459
- } catch (error) {
1460
- console.log("perpClient openPosition error:", error)
1461
- }
1462
- return instructions;
1463
- }
1464
-
1465
- // ==== OLD
1466
- // TODO: handle SOL wrapping to WSOL and create a ATA - NOT NEEDED
1467
- // TODO : Balance checks - NOT NEEDED
1468
- // TODO: ATA check - else create - DONE
1469
- // TODO: for close Accounts - DONE BY ANCHOR
1470
- // TODO : if out token WSOL -> unwrap to SOL - DONE
1471
- closePositionOld = async (
1472
- receivingTokenSymbol: string,
1473
- priceAfterSlippage: BN,
1474
- side: Side,
1475
- poolConfig: PoolConfig
1476
- ): Promise<TransactionInstruction[]> => {
1477
-
1478
- console.log("close position :::", receivingTokenSymbol, poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey.toBase58());
1479
-
1480
- // opp during close
1481
- // const slippageMultiplier = isVariant(side, 'short') ? -1 : 1;
1482
- // const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
1483
-
1484
- let publicKey = this.provider.wallet.publicKey;
1485
-
1486
- let userReceivingTokenAccount = await getAssociatedTokenAddress(
1487
- poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey,
1488
- publicKey
1489
- );
1490
- const instructions = [];
1491
- try {
1492
-
1493
- if (!(await checkIfAccountExists(userReceivingTokenAccount, this.provider.connection))) {
1494
- instructions.push(
1495
- createAssociatedTokenAccountInstruction(
1496
- publicKey,
1497
- userReceivingTokenAccount,
1498
- publicKey,
1499
- poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey
1500
- )
1501
- );
1502
- }
1503
-
1504
- const receivingTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey))!;
1505
-
1506
- // replace with getPositionKey
1507
- let positionAccount = PublicKey.findProgramAddressSync(
1508
- [
1509
- Buffer.from("position"),
1510
- publicKey.toBuffer(),
1511
- poolConfig.poolAddress.toBuffer(),
1512
- receivingTokenCustody.custodyAccount.toBuffer(),
1513
- isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
1514
- ],
1515
- this.programId
1516
- )[0];
1517
-
1518
- console.log("positionAccount:", positionAccount.toBase58())
1519
- const params: any = {
1520
- price: priceAfterSlippage,
1521
- };
1522
-
1523
- let instruction = await this.program.methods
1524
- .closePosition(params)
1525
- .accounts({
1526
- owner: publicKey,
1527
- receivingAccount: userReceivingTokenAccount,
1528
- transferAuthority: poolConfig.transferAuthority,
1529
- perpetuals: poolConfig.perpetuals,
1530
- pool: poolConfig.poolAddress,
1531
- position: positionAccount,
1532
- custody: receivingTokenCustody.custodyAccount,
1533
- custodyOracleAccount:
1534
- receivingTokenCustody.oracleAddress,
1535
- custodyTokenAccount:
1536
- receivingTokenCustody.tokenAccount,
1537
- tokenProgram: TOKEN_PROGRAM_ID,
1538
- }).instruction();
1539
- instructions.push(instruction)
1540
-
1541
- // SOL is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.
1542
- if (receivingTokenSymbol == 'SOL') {
1543
- // await closeAccount()
1544
- const closeWsolATAIns = createCloseAccountInstruction(userReceivingTokenAccount, publicKey, publicKey);
1545
- instructions.push(closeWsolATAIns);
1546
- }
1547
- } catch (error) {
1548
- console.error("perpclient closePosition error:", error);
1549
- }
1550
-
1551
- return instructions;
1552
- }
1553
-
1554
-
1555
-
1556
- // TODO: ATA check - else create - DONE
1557
- // TODO: handle SOL wrapping to WSOL and create a ATA - DONE
1558
- // TODO : Balance checks - NOT NEEDED
1559
- // TODO: for close Accounts - DONE BY ANCHOR
1560
- // TODO : if out token WSOL -> unwrap to SOL - DONE
1561
- swap = async (
1562
- poolReceivingTokenSymbol: string,
1563
- poolDispensingTokenSymbol: string,
1564
- amountIn: BN,
1565
- minAmountOut: BN,
1566
- poolConfig: PoolConfig,
1567
- unWrapSol = false
1568
- ): Promise<TransactionInstruction[]> => {
1569
-
1570
- const userReceivingTokenSymbol = poolDispensingTokenSymbol;
1571
- const userDispensingTokenSymbol= poolReceivingTokenSymbol;
1572
-
1573
- const poolReceivingCustodyConfig = poolConfig.custodies.find(
1574
- (i) => i.mintKey.toBase58() === poolConfig.getTokenFromSymbol(poolReceivingTokenSymbol).mintKey.toBase58()
1575
- );
1576
- if (!poolReceivingCustodyConfig) {
1577
- throw "receivingTokenCustody not found";
1578
- }
1579
- const poolDispensingCustodyConfig = poolConfig.custodies.find(
1580
- (i) => i.mintKey.toBase58() === poolConfig.getTokenFromSymbol(poolDispensingTokenSymbol).mintKey.toBase58()
1581
- );
1582
- if (!poolDispensingCustodyConfig) {
1583
- throw "dispensingTokenCustody not found";
1584
- }
1585
- let publicKey = this.provider.wallet.publicKey;
1586
-
1587
-
1588
- const instructions = [];
1589
- try {
1590
- let userReceivingTokenAccount = await getAssociatedTokenAddress(
1591
- poolDispensingCustodyConfig.mintKey,
1592
- publicKey
1593
- );
1594
- if (!(await checkIfAccountExists(userReceivingTokenAccount, this.provider.connection))) {
1595
- instructions.push(
1596
- createAssociatedTokenAccountInstruction(
1597
- publicKey,
1598
- userReceivingTokenAccount,
1599
- publicKey,
1600
- poolDispensingCustodyConfig.mintKey
1601
- )
1602
- );
1603
- }
1604
-
1605
- let userDispensingCustodyTokenAccount = await getAssociatedTokenAddress(
1606
- poolReceivingCustodyConfig.mintKey,
1607
- publicKey
1608
- );
1609
- // handle Wrapping of SOL if user input token is SOL
1610
- if (userDispensingTokenSymbol == 'SOL') {
1611
- console.log("userDispensingTokenSymbol === sol", userDispensingTokenSymbol);
1612
- const wsolAssociatedTokenAccount = await getAssociatedTokenAddress(
1613
- NATIVE_MINT,
1614
- publicKey
1615
- );
1616
- const wsolATAExist = await checkIfAccountExists(wsolAssociatedTokenAccount, this.provider.connection)
1617
- if (!wsolATAExist) {
1618
- console.log("wsol ata does not exist");
1619
- instructions.push(
1620
- createAssociatedTokenAccountInstruction(
1621
- publicKey,
1622
- wsolAssociatedTokenAccount,
1623
- publicKey,
1624
- NATIVE_MINT
1625
- )
1626
- );
1627
- }
1628
-
1629
- // get balance of WSOL associated token account
1630
- const wsolBalance = new BN(wsolATAExist ? (await this.provider.connection.getTokenAccountBalance(wsolAssociatedTokenAccount)).value.amount : 0);
1631
- if (wsolBalance.lt(amountIn)) {
1632
- // console.log("WSOL balance insufficient");
1633
- // so Convert SOL to WSOL
1634
- let unWrappedSolBalance = new BN(await this.provider.connection.getBalance(publicKey));
1635
- const totalSolBal = unWrappedSolBalance.add(wsolBalance);
1636
- if (totalSolBal.lt(amountIn)) {
1637
- throw "Insufficient SOL Funds"
1638
- }
1639
-
1640
- let conversionAmt = amountIn.sub(wsolBalance);
1641
- instructions.push(
1642
- SystemProgram.transfer({
1643
- fromPubkey: publicKey,
1644
- toPubkey: wsolAssociatedTokenAccount,
1645
- lamports: conversionAmt.toNumber(), // IS IT SAFE TO PUT AS NUMBER ?
1646
- }),
1647
- createSyncNativeInstruction(wsolAssociatedTokenAccount)
1648
- );
1649
- }
1650
- } else {
1651
- if (!(await checkIfAccountExists(userDispensingCustodyTokenAccount, this.provider.connection))) {
1652
- throw "Insufficient Funds , Token Account doesn't exist"
1653
- }
1654
- const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(userDispensingCustodyTokenAccount)).value.amount);
1655
- if (tokenAccountBalance.lt(amountIn)) {
1656
- throw "Insufficient Funds"
1657
- }
1658
- }
1659
-
1660
- const params = {
1661
- amountIn,
1662
- minAmountOut,
1663
- };
1664
- let inx = await this.program.methods
1665
- .swap(params)
1666
- .accounts({
1667
- owner: publicKey,
1668
- fundingAccount: userDispensingCustodyTokenAccount,
1669
- receivingAccount: userReceivingTokenAccount,
1670
- transferAuthority: poolConfig.transferAuthority,
1671
- perpetuals: poolConfig.perpetuals,
1672
- pool: poolConfig.poolAddress,
1673
-
1674
- receivingCustody: poolReceivingCustodyConfig.custodyAccount,
1675
- receivingCustodyOracleAccount: poolReceivingCustodyConfig.oracleAddress,
1676
- receivingCustodyTokenAccount: poolReceivingCustodyConfig.tokenAccount,
1677
-
1678
- dispensingCustody: poolDispensingCustodyConfig.custodyAccount,
1679
- dispensingCustodyOracleAccount: poolDispensingCustodyConfig.oracleAddress,
1680
- dispensingCustodyTokenAccount: poolDispensingCustodyConfig.tokenAccount,
1681
- tokenProgram: TOKEN_PROGRAM_ID,
1682
- })
1683
- .instruction();
1684
-
1685
- instructions.push(inx)
1686
-
1687
- // SOL is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.
1688
- if (userReceivingTokenSymbol == 'SOL' && unWrapSol) {
1689
- // await closeAccount()
1690
- const closeWsolATAIns = createCloseAccountInstruction(userReceivingTokenAccount, publicKey, publicKey);
1691
- instructions.push(closeWsolATAIns);
1692
- }
1693
-
1694
- } catch (err) {
1695
- console.error("perpClient Swap error:: ", err);
1696
- throw err;
1697
- }
1698
-
1699
- return instructions;
1700
- }
1701
-
1702
- // TODO: handle SOL wrapping to WSOL and create a ATA - DONE
1703
- // TODO :Balance checks - DONE
1704
- // TODO: ATA check - else create - DONE
1705
- // TODO: for close Accounts - NOT NEEDED
1706
- addLiquidity = async (
1707
- payTokenSymbol: string,
1708
- tokenAmountIn: BN,
1709
- minLpAmountOut: BN, // give this value based on slippage
1710
- poolConfig: PoolConfig
1711
- ): Promise<TransactionInstruction[]> => {
1712
-
1713
- const payTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey))!;
1714
- if (!payTokenCustody) {
1715
- throw "payTokenCustody not found";
1716
- }
1717
- let publicKey = this.provider.wallet.publicKey;
1718
-
1719
- const instructions = [];
1720
- try {
1721
-
1722
- let userPayingTokenAccount = await getAssociatedTokenAddress(
1723
- payTokenCustody.mintKey,
1724
- publicKey
1725
- );
1726
-
1727
- let lpTokenAccount = await getAssociatedTokenAddress(
1728
- poolConfig.lpTokenMint,
1729
- publicKey
1730
- );
1731
-
1732
- let custodyAccountMetas = [];
1733
- let custodyOracleAccountMetas = [];
1734
- for (const custody of poolConfig.custodies) {
1735
- custodyAccountMetas.push({
1736
- pubkey: custody.custodyAccount,
1737
- isSigner: false,
1738
- isWritable: false,
1739
- });
1740
-
1741
- custodyOracleAccountMetas.push({
1742
- pubkey: custody.oracleAddress,
1743
- isSigner: false,
1744
- isWritable: false,
1745
- });
1746
- }
1747
-
1748
- if (!(await checkIfAccountExists(lpTokenAccount, this.provider.connection))) {
1749
- instructions.push(
1750
- createAssociatedTokenAccountInstruction(
1751
- publicKey,
1752
- lpTokenAccount,
1753
- publicKey,
1754
- poolConfig.lpTokenMint
1755
- )
1756
- );
1757
- }
1758
-
1759
- if (payTokenSymbol == 'SOL') {
1760
- console.log("payTokenSymbol === sol", payTokenSymbol);
1761
- const wsolAssociatedTokenAccount = await getAssociatedTokenAddress(
1762
- NATIVE_MINT,
1763
- publicKey
1764
- );
1765
-
1766
- const wsolATAExist = await checkIfAccountExists(wsolAssociatedTokenAccount, this.provider.connection)
1767
- if (!wsolATAExist) {
1768
- console.log("wsol ata does not exist");
1769
- instructions.push(
1770
- createAssociatedTokenAccountInstruction(
1771
- publicKey,
1772
- wsolAssociatedTokenAccount,
1773
- publicKey,
1774
- NATIVE_MINT
1775
- )
1776
- );
1777
- }
1778
-
1779
- // get balance of WSOL associated token account
1780
- const wsolBalance = new BN(wsolATAExist ? (await this.provider.connection.getTokenAccountBalance(wsolAssociatedTokenAccount)).value.amount : 0);
1781
- if (wsolBalance.lt(tokenAmountIn)) {
1782
- // console.log("WSOL balance insufficient");
1783
- // so Convert SOL to WSOL
1784
- let unWrappedSolBalance = new BN(await this.provider.connection.getBalance(publicKey));
1785
- const totalSolBal = unWrappedSolBalance.add(wsolBalance);
1786
- if (totalSolBal.lt(tokenAmountIn)) {
1787
- throw "Insufficient SOL Funds"
1788
- }
1789
-
1790
- let conversionAmt = tokenAmountIn.sub(wsolBalance);
1791
- instructions.push(
1792
- SystemProgram.transfer({
1793
- fromPubkey: publicKey,
1794
- toPubkey: wsolAssociatedTokenAccount,
1795
- lamports: conversionAmt.toNumber(), // IS IT SAFE TO PUT AS NUMBER
1796
- }),
1797
- createSyncNativeInstruction(wsolAssociatedTokenAccount)
1798
- );
1799
- }
1800
- } else {
1801
- if (!(await checkIfAccountExists(userPayingTokenAccount, this.provider.connection))) {
1802
- throw "Insufficient Funds , token Account doesn't exist"
1803
- }
1804
- const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(userPayingTokenAccount)).value.amount);
1805
- if (tokenAccountBalance.lt(tokenAmountIn)) {
1806
- throw "Insufficient Funds"
1807
- }
1808
- }
1809
-
1810
- // console.log("in add liq", tokenAmountIn);
1811
-
1812
- let inx = await this.program.methods
1813
- .addLiquidity({
1814
- amountIn: tokenAmountIn,
1815
- minLpAmountOut
1816
- })
1817
- .accounts({
1818
- owner: publicKey,
1819
- fundingAccount: userPayingTokenAccount, // user token account for custody token account
1820
- lpTokenAccount,
1821
- transferAuthority: poolConfig.transferAuthority,
1822
- perpetuals: poolConfig.perpetuals,
1823
- pool: poolConfig.poolAddress,
1824
- custody: payTokenCustody.custodyAccount,
1825
- custodyOracleAccount: payTokenCustody.oracleAddress,
1826
- custodyTokenAccount: payTokenCustody.tokenAccount,
1827
- lpTokenMint: poolConfig.lpTokenMint,
1828
- tokenProgram: TOKEN_PROGRAM_ID,
1829
- })
1830
- .remainingAccounts([...custodyAccountMetas, ...custodyOracleAccountMetas])
1831
- .instruction();
1832
-
1833
- instructions.push(inx)
1834
- } catch (err) {
1835
- console.error("perpClient addLiquidity error:: ", err);
1836
- throw err;
1837
- }
1838
-
1839
- return instructions;
1840
- }
1841
- // TODO: handle SOL wrapping to WSOL and create a ATA - NOT NEEDED
1842
- // TODO :Balance checks - DONE
1843
- // TODO: ATA check - else create - DONE
1844
- // TODO: for LP close Accounts - DONE
1845
- // TODO : if out token WSOL -> unwrap to SOL - DONE
1846
- removeLiquidity = async (
1847
- recieveTokenSymbol: string,
1848
- liquidityAmountIn: BN,
1849
- minTokenAmountOut: BN, // give this value based on slippage
1850
- poolConfig: PoolConfig,
1851
- closeLpATA = false
1852
- ): Promise<TransactionInstruction[]> => {
1853
-
1854
- const recieveTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(recieveTokenSymbol).mintKey))!;
1855
- if (!recieveTokenCustody) {
1856
- throw "recieveTokenCustody not found";
1857
- }
1858
- let publicKey = this.provider.wallet.publicKey;
1859
-
1860
- const instructions = [];
1861
- try {
1862
- let userRecievingTokenAccount = await getAssociatedTokenAddress(
1863
- recieveTokenCustody.mintKey,
1864
- publicKey
1865
- );
1866
-
1867
- if (!(await checkIfAccountExists(userRecievingTokenAccount, this.provider.connection))) {
1868
- instructions.push(
1869
- createAssociatedTokenAccountInstruction(
1870
- publicKey,
1871
- userRecievingTokenAccount,
1872
- publicKey,
1873
- recieveTokenCustody.mintKey
1874
- )
1875
- );
1876
- }
1877
- let lpTokenAccount = await getAssociatedTokenAddress(
1878
- poolConfig.lpTokenMint,
1879
- publicKey
1880
- );
1881
-
1882
- let custodyAccountMetas = [];
1883
- let custodyOracleAccountMetas = [];
1884
- for (const custody of poolConfig.custodies) {
1885
- custodyAccountMetas.push({
1886
- pubkey: custody.custodyAccount,
1887
- isSigner: false,
1888
- isWritable: false,
1889
- });
1890
-
1891
- custodyOracleAccountMetas.push({
1892
- pubkey: custody.oracleAddress,
1893
- isSigner: false,
1894
- isWritable: false,
1895
- });
1896
- }
1897
-
1898
- console.log("liquidityAmountIn", liquidityAmountIn.toString());
1899
-
1900
- let removeLiquidityTx = await this.program.methods
1901
- .removeLiquidity({
1902
- lpAmountIn: liquidityAmountIn,
1903
- minAmountOut: minTokenAmountOut
1904
- })
1905
- .accounts({
1906
- owner: publicKey,
1907
- receivingAccount: userRecievingTokenAccount, // user token account for custody token account
1908
- lpTokenAccount,
1909
- transferAuthority: poolConfig.transferAuthority,
1910
- perpetuals: poolConfig.perpetuals,
1911
- pool: poolConfig.poolAddress,
1912
- custody: recieveTokenCustody.custodyAccount,
1913
- custodyOracleAccount: recieveTokenCustody.oracleAddress,
1914
- custodyTokenAccount: recieveTokenCustody.tokenAccount,
1915
- lpTokenMint: poolConfig.lpTokenMint,
1916
- tokenProgram: TOKEN_PROGRAM_ID,
1917
- })
1918
- .remainingAccounts([...custodyAccountMetas, ...custodyOracleAccountMetas])
1919
- .instruction();
1920
- instructions.push(removeLiquidityTx)
1921
-
1922
- if (closeLpATA) {
1923
- const closeInx = createCloseAccountInstruction(lpTokenAccount, publicKey, publicKey);
1924
- instructions.push(closeInx);
1925
- }
1926
-
1927
- // SOL is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.
1928
- if (recieveTokenSymbol == 'SOL') {
1929
- // await closeAccount()
1930
- const closeWsolATAIns = createCloseAccountInstruction(userRecievingTokenAccount, publicKey, publicKey);
1931
- instructions.push(closeWsolATAIns);
1932
- }
1933
-
1934
- } catch (err) {
1935
- console.log("perpClient removeLiquidity error:: ", err);
1936
- throw err;
1937
- }
1938
-
1939
- return instructions;
1940
- }
1941
-
1942
- public async sendTransaction(
1943
- ixs: TransactionInstruction[],
1944
- opts: any = {},
1945
- ): Promise<string> {
1946
- return await sendTransaction(
1947
- this.program.provider as AnchorProvider,
1948
- ixs,
1949
- opts.alts ?? [],
1950
- {
1951
- postSendTxCallback: this.postSendTxCallback,
1952
- prioritizationFee: this.prioritizationFee,
1953
- txConfirmationCommitment: this.txConfirmationCommitment,
1954
- ...opts,
1955
- },
1956
- );
1957
- }
1958
-
1959
- }
1960
-
1961
-