flash-sdk 1.0.22 → 1.0.24

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