flash-sdk 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/CustodyAccount.js +9 -19
- package/lib/OraclePrice.d.ts +2 -0
- package/lib/OraclePrice.js +4 -0
- package/lib/PerpetualsClient.d.ts +24 -5
- package/lib/PerpetualsClient.js +604 -24
- package/lib/PoolAccount.d.ts +2 -1
- package/lib/PoolAccount.js +16 -29
- package/lib/PoolConfig.d.ts +7 -2
- package/lib/PoolConfig.js +15 -7
- package/lib/PoolConfig.json +4 -0
- package/lib/{PoolDisplayData.d.ts → PoolDataClient.d.ts} +3 -2
- package/lib/{PoolDisplayData.js → PoolDataClient.js} +13 -13
- package/lib/PositionAccount.d.ts +1 -0
- package/lib/Token.js +1 -0
- package/lib/constants/index.d.ts +1 -0
- package/lib/idl/perpetuals.d.ts +3675 -0
- package/{src/target/types → lib/idl}/perpetuals.js +140 -3
- package/lib/index.d.ts +3 -0
- package/lib/index.js +5 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/index.d.ts +5 -3
- package/lib/types/index.js +21 -1
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +57 -1
- package/lib/utils/rpc.d.ts +13 -0
- package/lib/utils/rpc.js +217 -0
- package/package.json +1 -1
- package/src/CustodyAccount.ts +24 -23
- package/src/OraclePrice.ts +4 -4
- package/src/PerpetualsClient.ts +763 -96
- package/src/PoolAccount.ts +34 -32
- package/src/PoolConfig.json +4 -0
- package/src/PoolConfig.ts +21 -6
- package/src/{PoolDisplayData.ts → PoolDataClient.ts} +2 -2
- package/src/Token.ts +1 -0
- package/src/{target/types → idl}/perpetuals.ts +280 -6
- package/src/index.ts +3 -0
- package/src/types/index.ts +26 -3
- package/src/utils/index.ts +14 -0
- package/src/utils/rpc.ts +162 -0
- package/lib/CustodyAccount.d.ts.map +0 -1
- package/lib/CustodyAccount.js.map +0 -1
- package/lib/OraclePrice.d.ts.map +0 -1
- package/lib/OraclePrice.js.map +0 -1
- package/lib/PerpetualsClient.d.ts.map +0 -1
- package/lib/PerpetualsClient.js.map +0 -1
- package/lib/PoolAccount.d.ts.map +0 -1
- package/lib/PoolAccount.js.map +0 -1
- package/lib/PositionAccount.d.ts.map +0 -1
- package/lib/PositionAccount.js.map +0 -1
- package/lib/client/src/CustodyAccount.d.ts +0 -30
- package/lib/client/src/CustodyAccount.d.ts.map +0 -1
- package/lib/client/src/CustodyAccount.js +0 -64
- package/lib/client/src/CustodyAccount.js.map +0 -1
- package/lib/client/src/OraclePrice.d.ts +0 -19
- package/lib/client/src/OraclePrice.d.ts.map +0 -1
- package/lib/client/src/OraclePrice.js +0 -84
- package/lib/client/src/OraclePrice.js.map +0 -1
- package/lib/client/src/PerpetualsClient.d.ts +0 -1938
- package/lib/client/src/PerpetualsClient.d.ts.map +0 -1
- package/lib/client/src/PerpetualsClient.js +0 -1043
- package/lib/client/src/PerpetualsClient.js.map +0 -1
- package/lib/client/src/PoolAccount.d.ts +0 -35
- package/lib/client/src/PoolAccount.d.ts.map +0 -1
- package/lib/client/src/PoolAccount.js +0 -307
- package/lib/client/src/PoolAccount.js.map +0 -1
- package/lib/client/src/PositionAccount.d.ts +0 -27
- package/lib/client/src/PositionAccount.d.ts.map +0 -1
- package/lib/client/src/PositionAccount.js +0 -91
- package/lib/client/src/PositionAccount.js.map +0 -1
- package/lib/client/src/constants/index.d.ts +0 -12
- package/lib/client/src/constants/index.d.ts.map +0 -1
- package/lib/client/src/constants/index.js +0 -15
- package/lib/client/src/constants/index.js.map +0 -1
- package/lib/client/src/index.d.ts +0 -9
- package/lib/client/src/index.d.ts.map +0 -1
- package/lib/client/src/index.js +0 -26
- package/lib/client/src/index.js.map +0 -1
- package/lib/client/src/types/index.d.ts +0 -188
- package/lib/client/src/types/index.d.ts.map +0 -1
- package/lib/client/src/types/index.js +0 -57
- package/lib/client/src/types/index.js.map +0 -1
- package/lib/client/src/utils/helpers.d.ts +0 -8
- package/lib/client/src/utils/helpers.d.ts.map +0 -1
- package/lib/client/src/utils/helpers.js +0 -152
- package/lib/client/src/utils/helpers.js.map +0 -1
- package/lib/constants/index.d.ts.map +0 -1
- package/lib/constants/index.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/index.js.map +0 -1
- package/lib/utils/helpers.d.ts +0 -7
- package/lib/utils/helpers.d.ts.map +0 -1
- package/lib/utils/helpers.js +0 -151
- package/lib/utils/helpers.js.map +0 -1
- package/src/target/types/limit_order_cpi.js +0 -132
- package/src/target/types/limit_order_cpi.ts +0 -259
- /package/{src/target/idl/perpetuals.json → lib/Token.d.ts} +0 -0
- /package/src/{readme.md → type-rules.md} +0 -0
package/src/PerpetualsClient.ts
CHANGED
@@ -14,6 +14,8 @@ import {
|
|
14
14
|
AccountMeta,
|
15
15
|
Keypair,
|
16
16
|
SYSVAR_RENT_PUBKEY,
|
17
|
+
Commitment,
|
18
|
+
LAMPORTS_PER_SOL,
|
17
19
|
} from "@solana/web3.js";
|
18
20
|
import {
|
19
21
|
getAccount,
|
@@ -22,22 +24,26 @@ import {
|
|
22
24
|
createCloseAccountInstruction,
|
23
25
|
createSyncNativeInstruction,
|
24
26
|
TOKEN_PROGRAM_ID,
|
27
|
+
NATIVE_MINT,
|
25
28
|
} from "@solana/spl-token";
|
26
29
|
|
27
30
|
import { sha256 } from "js-sha256";
|
28
31
|
import { encode } from "bs58";
|
29
32
|
import { PoolAccount } from "./PoolAccount";
|
30
33
|
import { PositionAccount } from "./PositionAccount";
|
31
|
-
import { BorrowRateParams, Custody, Fees, OracleParams, Permissions, Position, PositionSide, PricingParams, TokenRatios, isVariant } from "./types";
|
34
|
+
import { AumCalcMode, BorrowRateParams, Custody, Fees, OracleParams, Permissions, Position, PositionSide, PricingParams, Side, TokenRatios, isVariant } from "./types";
|
32
35
|
import { OraclePrice } from "./OraclePrice";
|
33
36
|
import { CustodyAccount } from "./CustodyAccount";
|
34
|
-
import { Perpetuals } from "./
|
35
|
-
import {IDL}
|
37
|
+
import { Perpetuals } from "./idl/perpetuals";
|
38
|
+
import { IDL } from './idl/perpetuals';
|
39
|
+
import { sendTransaction } from "./utils/rpc";
|
40
|
+
import { PoolConfig } from "./PoolConfig";
|
41
|
+
import { checkIfAccountExists } from "./utils";
|
36
42
|
|
37
43
|
|
38
44
|
/* USEAGE
|
39
45
|
|
40
|
-
UI
|
46
|
+
UI -----
|
41
47
|
provider = from phatom
|
42
48
|
|
43
49
|
client = new PerpetualsClient(provider, user.pubkey , programId);
|
@@ -56,6 +62,13 @@ process.env["ANCHOR_WALLET"] = adminKeyPath;
|
|
56
62
|
client = new PerpetualsClient(provider, DEFAULT_PERPS_USER.pubkey , programId);
|
57
63
|
|
58
64
|
*/
|
65
|
+
|
66
|
+
export type PerpClientOptions = {
|
67
|
+
postSendTxCallback?: ({ txid }: { txid: string }) => void;
|
68
|
+
prioritizationFee?: number;
|
69
|
+
txConfirmationCommitment?: Commitment;
|
70
|
+
};
|
71
|
+
|
59
72
|
export class PerpetualsClient {
|
60
73
|
provider: AnchorProvider;
|
61
74
|
program: Program<Perpetuals>;
|
@@ -67,7 +80,11 @@ export class PerpetualsClient {
|
|
67
80
|
authority: { publicKey: PublicKey; bump: number };
|
68
81
|
perpetuals: { publicKey: PublicKey; bump: number };
|
69
82
|
|
70
|
-
|
83
|
+
private postSendTxCallback?: ({ txid }) => void;
|
84
|
+
private prioritizationFee: number;
|
85
|
+
private txConfirmationCommitment: Commitment;
|
86
|
+
|
87
|
+
constructor(provider: AnchorProvider, programId: PublicKey, opts: PerpClientOptions) {
|
71
88
|
// this.provider = AnchorProvider.local(clusterUrl, {
|
72
89
|
// commitment: "confirmed",
|
73
90
|
// preflightCommitment: "confirmed",
|
@@ -80,27 +97,32 @@ export class PerpetualsClient {
|
|
80
97
|
// const idl = JSON.parse( fs.readFileSync("./target/idl/perpetuals.json", "utf8"));
|
81
98
|
// const idl = JSON.parse(IDL);
|
82
99
|
// const program = new anchor.Program(idl, programId, provider);
|
83
|
-
this.program = new Program(IDL, programId);
|
100
|
+
this.program = new Program(IDL, programId);
|
101
|
+
this.programId = programId;
|
84
102
|
//this.program = workspace.Perpetuals as Program<Perpetuals>;
|
85
|
-
console.log("client constructor programID : ",this.program.programId.toBase58());
|
103
|
+
console.log("client constructor programID : ", this.program.programId.toBase58());
|
86
104
|
|
87
105
|
// this.admin = Keypair.fromSecretKey(
|
88
106
|
// new Uint8Array(JSON.parse(readFileSync(adminKey).toString()))
|
89
107
|
// );
|
90
108
|
|
91
|
-
this.admin =
|
92
|
-
console.log("admin:",this.admin.toBase58())
|
109
|
+
this.admin = this.provider.wallet.publicKey;
|
110
|
+
console.log("admin:", this.admin.toBase58())
|
93
111
|
|
94
112
|
this.multisig = this.findProgramAddress("multisig");
|
95
113
|
this.authority = this.findProgramAddress("transfer_authority");
|
96
114
|
this.perpetuals = this.findProgramAddress("perpetuals");
|
97
115
|
|
116
|
+
this.prioritizationFee = opts?.prioritizationFee || 0;
|
117
|
+
this.postSendTxCallback = opts?.postSendTxCallback;
|
118
|
+
this.txConfirmationCommitment = opts?.txConfirmationCommitment ?? 'processed'
|
119
|
+
|
98
120
|
BN.prototype.toJSON = function () {
|
99
121
|
return this.toString(10);
|
100
122
|
};
|
101
123
|
}
|
102
124
|
|
103
|
-
findProgramAddress = (label: string, extraSeeds
|
125
|
+
findProgramAddress = (label: string, extraSeeds: any = null) => {
|
104
126
|
let seeds = [Buffer.from(utils.bytes.utf8.encode(label))];
|
105
127
|
if (extraSeeds) {
|
106
128
|
for (let extraSeed of extraSeeds) {
|
@@ -117,7 +139,7 @@ export class PerpetualsClient {
|
|
117
139
|
return { publicKey: res[0], bump: res[1] };
|
118
140
|
};
|
119
141
|
|
120
|
-
adjustTokenRatios = (ratios
|
142
|
+
adjustTokenRatios = (ratios: TokenRatios[]) => {
|
121
143
|
if (ratios.length == 0) {
|
122
144
|
return ratios;
|
123
145
|
}
|
@@ -145,7 +167,7 @@ export class PerpetualsClient {
|
|
145
167
|
};
|
146
168
|
|
147
169
|
getPool = async (name: string) => {
|
148
|
-
console.log("pool:",this.getPoolKey(name).toBase58())
|
170
|
+
console.log("pool:", this.getPoolKey(name).toBase58())
|
149
171
|
return this.program.account.pool.fetch(this.getPoolKey(name));
|
150
172
|
};
|
151
173
|
|
@@ -189,7 +211,7 @@ export class PerpetualsClient {
|
|
189
211
|
};
|
190
212
|
|
191
213
|
getCustody = async (poolName: string, tokenMint: PublicKey) => {
|
192
|
-
console.log("custody key :",this.getCustodyKey(poolName, tokenMint).toBase58());
|
214
|
+
console.log("custody key :", this.getCustodyKey(poolName, tokenMint).toBase58());
|
193
215
|
return this.program.account.custody.fetch(
|
194
216
|
this.getCustodyKey(poolName, tokenMint)
|
195
217
|
);
|
@@ -197,7 +219,7 @@ export class PerpetualsClient {
|
|
197
219
|
|
198
220
|
getCustodies = async (poolName: string) => {
|
199
221
|
//return this.program.account.custody.all();
|
200
|
-
let pool
|
222
|
+
let pool = await this.getPool(poolName);
|
201
223
|
return this.program.account.custody.fetchMultiple(
|
202
224
|
pool.custodies
|
203
225
|
);
|
@@ -205,7 +227,7 @@ export class PerpetualsClient {
|
|
205
227
|
|
206
228
|
getCustodyMetas = async (poolName: string) => {
|
207
229
|
let pool = await this.getPool(poolName);
|
208
|
-
let custodies
|
230
|
+
let custodies: any = await this.program.account.custody.fetchMultiple(
|
209
231
|
pool.custodies
|
210
232
|
);
|
211
233
|
let custodyMetas = [];
|
@@ -246,7 +268,7 @@ export class PerpetualsClient {
|
|
246
268
|
]).publicKey;
|
247
269
|
};
|
248
270
|
|
249
|
-
getPosition = async (postionKey
|
271
|
+
getPosition = async (postionKey: PublicKey) => {
|
250
272
|
return this.program.account.position.fetch(postionKey);
|
251
273
|
};
|
252
274
|
|
@@ -433,55 +455,55 @@ export class PerpetualsClient {
|
|
433
455
|
poolName: string,
|
434
456
|
tokenMint: PublicKey,
|
435
457
|
isStable: boolean,
|
436
|
-
oracle
|
458
|
+
oracle: OracleParams,
|
437
459
|
pricing: PricingParams,
|
438
|
-
permissions
|
439
|
-
fees
|
440
|
-
borrowRate
|
441
|
-
ratios
|
460
|
+
permissions: Permissions,
|
461
|
+
fees: Fees,
|
462
|
+
borrowRate: BorrowRateParams,
|
463
|
+
ratios: TokenRatios[]
|
442
464
|
) => {
|
443
|
-
console.log("CustodyKey",
|
444
|
-
console.log("getCustodyTokenAccountKey",
|
465
|
+
console.log("CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
|
466
|
+
console.log("getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
|
445
467
|
try {
|
446
|
-
const trx_id =
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
468
|
+
const trx_id = await this.program.methods
|
469
|
+
// @ts-ignore
|
470
|
+
.addCustody({
|
471
|
+
isStable,
|
472
|
+
oracle,
|
473
|
+
pricing,
|
474
|
+
permissions,
|
475
|
+
fees,
|
476
|
+
borrowRate,
|
477
|
+
ratios,
|
478
|
+
})
|
479
|
+
.accounts({
|
480
|
+
admin: this.admin,
|
481
|
+
multisig: this.multisig.publicKey,
|
482
|
+
transferAuthority: this.authority.publicKey,
|
483
|
+
perpetuals: this.perpetuals.publicKey,
|
484
|
+
pool: this.getPoolKey(poolName),
|
485
|
+
custody: this.getCustodyKey(poolName, tokenMint),
|
486
|
+
custodyTokenAccount: this.getCustodyTokenAccountKey(
|
487
|
+
poolName,
|
488
|
+
tokenMint
|
489
|
+
),
|
490
|
+
custodyTokenMint: tokenMint,
|
491
|
+
systemProgram: SystemProgram.programId,
|
492
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
493
|
+
rent: SYSVAR_RENT_PUBKEY,
|
494
|
+
})
|
495
|
+
// .signers([this.admin])
|
496
|
+
.rpc()
|
497
|
+
.catch((err) => {
|
498
|
+
console.error(err);
|
499
|
+
throw err;
|
500
|
+
});
|
479
501
|
|
480
502
|
console.log("trx_id:", `https://explorer.solana.com/tx/${trx_id}?cluster=devnet`)
|
481
503
|
} catch (error) {
|
482
|
-
console.log("cli error :",error);
|
504
|
+
console.log("cli error :", error);
|
483
505
|
}
|
484
|
-
|
506
|
+
|
485
507
|
|
486
508
|
};
|
487
509
|
|
@@ -489,18 +511,18 @@ export class PerpetualsClient {
|
|
489
511
|
poolName: string,
|
490
512
|
tokenMint: PublicKey,
|
491
513
|
isStable: boolean,
|
492
|
-
oracle
|
514
|
+
oracle: OracleParams,
|
493
515
|
pricing: PricingParams,
|
494
|
-
permissions
|
495
|
-
fees
|
496
|
-
borrowRate
|
497
|
-
ratios
|
516
|
+
permissions: Permissions,
|
517
|
+
fees: Fees,
|
518
|
+
borrowRate: BorrowRateParams,
|
519
|
+
ratios: TokenRatios[]
|
498
520
|
) => {
|
499
|
-
console.log("CustodyKey",
|
500
|
-
console.log("getCustodyTokenAccountKey",
|
521
|
+
console.log("CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
|
522
|
+
console.log("getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
|
501
523
|
|
502
|
-
|
503
|
-
|
524
|
+
const trx_id = await this.program.methods
|
525
|
+
//@ts-ignore
|
504
526
|
.testingEditCustody({
|
505
527
|
isStable,
|
506
528
|
oracle,
|
@@ -532,10 +554,10 @@ export class PerpetualsClient {
|
|
532
554
|
console.error(err);
|
533
555
|
throw err;
|
534
556
|
});
|
535
|
-
|
557
|
+
console.log("trx_id:", `https://explorer.solana.com/tx/${trx_id}?cluster=devnet`)
|
536
558
|
};
|
537
559
|
|
538
|
-
removeCustody = async (poolName: string, tokenMint: PublicKey, ratios:TokenRatios[]) => {
|
560
|
+
removeCustody = async (poolName: string, tokenMint: PublicKey, ratios: TokenRatios[]) => {
|
539
561
|
await this.program.methods
|
540
562
|
.removeCustody({ ratios })
|
541
563
|
.accounts({
|
@@ -646,7 +668,7 @@ export class PerpetualsClient {
|
|
646
668
|
amount: BN
|
647
669
|
) => {
|
648
670
|
return await this.program.methods
|
649
|
-
.getAddLiquidityAmountAndFee({
|
671
|
+
.getAddLiquidityAmountAndFee({
|
650
672
|
amountIn: amount,
|
651
673
|
})
|
652
674
|
.accounts({
|
@@ -667,8 +689,6 @@ export class PerpetualsClient {
|
|
667
689
|
});
|
668
690
|
};
|
669
691
|
|
670
|
-
|
671
|
-
|
672
692
|
getRemoveLiquidityAmountAndFee = async (
|
673
693
|
poolName: string,
|
674
694
|
tokenMint: PublicKey,
|
@@ -699,23 +719,23 @@ export class PerpetualsClient {
|
|
699
719
|
getEntryPriceAndFee = async (
|
700
720
|
poolName: string,
|
701
721
|
tokenMint: PublicKey,
|
702
|
-
collateral:
|
703
|
-
size:
|
722
|
+
collateral: BN,
|
723
|
+
size: BN,
|
704
724
|
side: PositionSide
|
705
725
|
) => {
|
706
726
|
console.log("perps: ", this.perpetuals.publicKey.toBase58())
|
707
727
|
|
708
728
|
console.log("poolKey: ", this.getPoolKey(poolName).toBase58())
|
709
|
-
console.log("custody key : ",this.getCustodyKey(poolName, tokenMint).toBase58());
|
710
|
-
console.log("orcalve: ",
|
729
|
+
console.log("custody key : ", this.getCustodyKey(poolName, tokenMint).toBase58());
|
730
|
+
console.log("orcalve: ", (await this.getCustodyOracleAccountKey(poolName, tokenMint)).toBase58())
|
711
731
|
|
712
732
|
//@ts-ignore
|
713
733
|
return await this.program.methods
|
714
|
-
|
715
|
-
.getEntryPriceAndFee({
|
734
|
+
//@ts-ignore
|
735
|
+
.getEntryPriceAndFee({
|
716
736
|
collateral,
|
717
737
|
size,
|
718
|
-
side: side == "long" ? { long: {} } : { short: {} },
|
738
|
+
side: side == "long" ? { long: {} } : { short: {} },
|
719
739
|
})
|
720
740
|
.accounts({
|
721
741
|
// signer: this.provider.wallet.publicKey,
|
@@ -886,7 +906,7 @@ export class PerpetualsClient {
|
|
886
906
|
side: PositionSide
|
887
907
|
) => {
|
888
908
|
const pos = this.getPositionKey(wallet, poolName, tokenMint, side);
|
889
|
-
console.log("pos:",pos.toBase58())
|
909
|
+
console.log("pos:", pos.toBase58())
|
890
910
|
return await this.program.methods
|
891
911
|
.getPnl({})
|
892
912
|
.accounts({
|
@@ -914,7 +934,7 @@ export class PerpetualsClient {
|
|
914
934
|
side: PositionSide
|
915
935
|
) => {
|
916
936
|
const pos = this.getPositionKey(wallet, poolName, tokenMint, side);
|
917
|
-
console.log("pos:",pos.toBase58())
|
937
|
+
console.log("pos:", pos.toBase58())
|
918
938
|
return await this.program.methods
|
919
939
|
.getPnl({})
|
920
940
|
.accounts({
|
@@ -935,33 +955,33 @@ export class PerpetualsClient {
|
|
935
955
|
};
|
936
956
|
|
937
957
|
|
938
|
-
getPnl2 =
|
939
|
-
postionKey
|
958
|
+
getPnl2 = (
|
959
|
+
postionKey: PublicKey,
|
940
960
|
postionData: Position,
|
941
|
-
tokenPrice
|
942
|
-
tokenEmaPrice
|
943
|
-
custodyAccount
|
944
|
-
poolAccount
|
945
|
-
currentTime
|
961
|
+
tokenPrice: OraclePrice,
|
962
|
+
tokenEmaPrice: OraclePrice,
|
963
|
+
custodyAccount: CustodyAccount,
|
964
|
+
poolAccount: PoolAccount,
|
965
|
+
currentTime: BN
|
946
966
|
) => {
|
947
|
-
|
967
|
+
|
948
968
|
const positionAccount = PositionAccount.from(postionKey, postionData);
|
949
969
|
// console.log("positionAccount:",positionAccount);
|
950
970
|
// console.log("side :", postionData.side, (isVariant(postionData.side, 'long')))
|
951
971
|
|
952
|
-
let {profit, loss, exitFee} = poolAccount.getPnlUsd(
|
972
|
+
let { profit, loss, exitFee } = poolAccount.getPnlUsd(
|
953
973
|
positionAccount,
|
954
974
|
tokenPrice,
|
955
975
|
tokenEmaPrice,
|
956
976
|
custodyAccount,
|
957
977
|
currentTime,
|
958
978
|
false,
|
959
|
-
|
979
|
+
);
|
960
980
|
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
981
|
+
return {
|
982
|
+
profit,
|
983
|
+
loss
|
984
|
+
}
|
965
985
|
|
966
986
|
}
|
967
987
|
|
@@ -996,7 +1016,7 @@ export class PerpetualsClient {
|
|
996
1016
|
});
|
997
1017
|
};
|
998
1018
|
|
999
|
-
|
1019
|
+
getAumView = async (poolName: string) => {
|
1000
1020
|
return await this.program.methods
|
1001
1021
|
.getAssetsUnderManagement({})
|
1002
1022
|
.accounts({
|
@@ -1010,4 +1030,651 @@ export class PerpetualsClient {
|
|
1010
1030
|
throw err;
|
1011
1031
|
});
|
1012
1032
|
};
|
1033
|
+
|
1034
|
+
getAumTrx = async (poolName: string) => {
|
1035
|
+
return await this.program.methods
|
1036
|
+
.getAssetsUnderManagement({})
|
1037
|
+
.accounts({
|
1038
|
+
perpetuals: this.perpetuals.publicKey,
|
1039
|
+
pool: this.getPoolKey(poolName),
|
1040
|
+
})
|
1041
|
+
.remainingAccounts(await this.getCustodyMetas(poolName))
|
1042
|
+
.rpc()
|
1043
|
+
.catch((err) => {
|
1044
|
+
console.error(err);
|
1045
|
+
throw err;
|
1046
|
+
});
|
1047
|
+
};
|
1048
|
+
|
1049
|
+
getAumSdk = (
|
1050
|
+
poolAccount: PoolAccount,
|
1051
|
+
token_prices: OraclePrice[],
|
1052
|
+
token_ema_prices: OraclePrice[],
|
1053
|
+
custodies: CustodyAccount[],
|
1054
|
+
aum_calc_mode: AumCalcMode,
|
1055
|
+
currentTime: BN
|
1056
|
+
) => {
|
1057
|
+
// console.log("poolAccount:",poolAccount);
|
1058
|
+
|
1059
|
+
return poolAccount.getAssetsUnderManagementUsd(
|
1060
|
+
token_prices,
|
1061
|
+
token_ema_prices,
|
1062
|
+
custodies,
|
1063
|
+
aum_calc_mode,
|
1064
|
+
currentTime
|
1065
|
+
);
|
1066
|
+
};
|
1067
|
+
|
1068
|
+
// TODO: handle SOL wrapping to WSOL and create a ATA - DONE
|
1069
|
+
// TODO: Balance checks - DONE
|
1070
|
+
// TODO: ATA check - else create - DONE
|
1071
|
+
// TODO: for close Accounts - NOT NEEDED
|
1072
|
+
openPosition = async (
|
1073
|
+
payTokenSymbol: string,
|
1074
|
+
price: BN,
|
1075
|
+
collateral: BN,
|
1076
|
+
size: BN,
|
1077
|
+
side: Side,
|
1078
|
+
slippagePercentage: number,
|
1079
|
+
poolConfig: PoolConfig
|
1080
|
+
): Promise<TransactionInstruction[]> => {
|
1081
|
+
|
1082
|
+
console.log("open position :::", payTokenSymbol, poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey.toBase58());
|
1083
|
+
|
1084
|
+
const slippageMultiplier = isVariant(side, 'long') ? -1 : 1;
|
1085
|
+
const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
|
1086
|
+
|
1087
|
+
let publicKey = this.provider.wallet.publicKey;
|
1088
|
+
const payTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey))!;
|
1089
|
+
|
1090
|
+
let userCustodyTokenAccount = await getAssociatedTokenAddress(
|
1091
|
+
poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey,
|
1092
|
+
publicKey
|
1093
|
+
);
|
1094
|
+
|
1095
|
+
const instructions = [];
|
1096
|
+
try {
|
1097
|
+
|
1098
|
+
if (payTokenSymbol == 'SOL') {
|
1099
|
+
console.log("payTokenSymbol === sol", payTokenSymbol);
|
1100
|
+
const wsolAssociatedTokenAccount = await getAssociatedTokenAddress(
|
1101
|
+
NATIVE_MINT,
|
1102
|
+
publicKey
|
1103
|
+
);
|
1104
|
+
const wsolATAExist = await checkIfAccountExists(wsolAssociatedTokenAccount, this.provider.connection)
|
1105
|
+
if (!wsolATAExist) {
|
1106
|
+
console.log("wsol ata does not exist");
|
1107
|
+
instructions.push(
|
1108
|
+
createAssociatedTokenAccountInstruction(
|
1109
|
+
publicKey,
|
1110
|
+
wsolAssociatedTokenAccount,
|
1111
|
+
publicKey,
|
1112
|
+
NATIVE_MINT
|
1113
|
+
)
|
1114
|
+
);
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
// get balance of WSOL associated token account
|
1118
|
+
const wsolBalance = new BN(wsolATAExist ? (await this.provider.connection.getTokenAccountBalance(wsolAssociatedTokenAccount)).value.amount : 0);
|
1119
|
+
if (wsolBalance.lt(collateral)) {
|
1120
|
+
// console.log("WSOL balance insufficient");
|
1121
|
+
// so Convert SOL to WSOL
|
1122
|
+
let unWrappedSolBalance = new BN(await this.provider.connection.getBalance(publicKey));
|
1123
|
+
const totalSolBal = unWrappedSolBalance.add(wsolBalance);
|
1124
|
+
if (totalSolBal.lt(collateral)) {
|
1125
|
+
throw "Insufficient SOL Funds"
|
1126
|
+
}
|
1127
|
+
|
1128
|
+
let conversionAmt = collateral.sub(wsolBalance);
|
1129
|
+
instructions.push(
|
1130
|
+
SystemProgram.transfer({
|
1131
|
+
fromPubkey: publicKey,
|
1132
|
+
toPubkey: wsolAssociatedTokenAccount,
|
1133
|
+
lamports: conversionAmt.toNumber(), // IS IT SAFE TO PUT AS NUMBER
|
1134
|
+
}),
|
1135
|
+
createSyncNativeInstruction(wsolAssociatedTokenAccount)
|
1136
|
+
);
|
1137
|
+
}
|
1138
|
+
} else {
|
1139
|
+
if (!(await checkIfAccountExists(userCustodyTokenAccount, this.provider.connection))) {
|
1140
|
+
throw "Insufficient Funds , token Account doesn't exist"
|
1141
|
+
}
|
1142
|
+
const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(userCustodyTokenAccount)).value.amount);
|
1143
|
+
if (tokenAccountBalance.lt(collateral)) {
|
1144
|
+
throw "Insufficient Funds"
|
1145
|
+
}
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
// replace with getPositionKey()
|
1149
|
+
let positionAccount = PublicKey.findProgramAddressSync(
|
1150
|
+
[
|
1151
|
+
Buffer.from("position"),
|
1152
|
+
publicKey.toBuffer(),
|
1153
|
+
poolConfig.poolAddress.toBuffer(),
|
1154
|
+
payTokenCustody.custodyAccount.toBuffer(),
|
1155
|
+
isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
|
1156
|
+
],
|
1157
|
+
this.programId
|
1158
|
+
)[0];
|
1159
|
+
|
1160
|
+
const params: any = {
|
1161
|
+
price: priceAfterSlippage,
|
1162
|
+
collateral,
|
1163
|
+
size,
|
1164
|
+
side,
|
1165
|
+
};
|
1166
|
+
|
1167
|
+
let instruction = await this.program.methods
|
1168
|
+
.openPosition(params)
|
1169
|
+
.accounts({
|
1170
|
+
owner: publicKey,
|
1171
|
+
fundingAccount: userCustodyTokenAccount,
|
1172
|
+
transferAuthority: poolConfig.transferAuthority,
|
1173
|
+
perpetuals: poolConfig.perpetuals,
|
1174
|
+
pool: poolConfig.poolAddress,
|
1175
|
+
position: positionAccount,
|
1176
|
+
custody: payTokenCustody.custodyAccount,
|
1177
|
+
custodyOracleAccount:
|
1178
|
+
payTokenCustody.oracleAddress,
|
1179
|
+
custodyTokenAccount:
|
1180
|
+
payTokenCustody.tokenAccount,
|
1181
|
+
systemProgram: SystemProgram.programId,
|
1182
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
1183
|
+
}).instruction()
|
1184
|
+
instructions.push(instruction);
|
1185
|
+
|
1186
|
+
} catch (error) {
|
1187
|
+
console.log("perpClient openPosition error:", error)
|
1188
|
+
}
|
1189
|
+
return instructions;
|
1190
|
+
}
|
1191
|
+
|
1192
|
+
// TODO: handle SOL wrapping to WSOL and create a ATA - NOT NEEDED
|
1193
|
+
// TODO : Balance checks - NOT NEEDED
|
1194
|
+
// TODO: ATA check - else create - DONE
|
1195
|
+
// TODO: for close Accounts - DONE BY ANCHOR
|
1196
|
+
// TODO : if out token WSOL -> unwrap to SOL - DONE
|
1197
|
+
closePosition = async (
|
1198
|
+
receivingTokenSymbol: string,
|
1199
|
+
price: BN,
|
1200
|
+
side: Side,
|
1201
|
+
slippagePercentage: number,
|
1202
|
+
poolConfig: PoolConfig
|
1203
|
+
): Promise<TransactionInstruction[]> => {
|
1204
|
+
|
1205
|
+
console.log("close position :::", receivingTokenSymbol, poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey.toBase58());
|
1206
|
+
|
1207
|
+
const slippageMultiplier = isVariant(side, 'long') ? -1 : 1;
|
1208
|
+
const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
|
1209
|
+
|
1210
|
+
let publicKey = this.provider.wallet.publicKey;
|
1211
|
+
|
1212
|
+
let userReceivingTokenAccount = await getAssociatedTokenAddress(
|
1213
|
+
poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey,
|
1214
|
+
publicKey
|
1215
|
+
);
|
1216
|
+
const instructions = [];
|
1217
|
+
try {
|
1218
|
+
|
1219
|
+
if (!(await checkIfAccountExists(userReceivingTokenAccount, this.provider.connection))) {
|
1220
|
+
instructions.push(
|
1221
|
+
createAssociatedTokenAccountInstruction(
|
1222
|
+
publicKey,
|
1223
|
+
userReceivingTokenAccount,
|
1224
|
+
publicKey,
|
1225
|
+
poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey
|
1226
|
+
)
|
1227
|
+
);
|
1228
|
+
}
|
1229
|
+
|
1230
|
+
const receivingTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey))!;
|
1231
|
+
|
1232
|
+
// replace with getPositionKey
|
1233
|
+
let positionAccount = PublicKey.findProgramAddressSync(
|
1234
|
+
[
|
1235
|
+
Buffer.from("position"),
|
1236
|
+
publicKey.toBuffer(),
|
1237
|
+
poolConfig.poolAddress.toBuffer(),
|
1238
|
+
receivingTokenCustody.custodyAccount.toBuffer(),
|
1239
|
+
isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
|
1240
|
+
],
|
1241
|
+
this.programId
|
1242
|
+
)[0];
|
1243
|
+
|
1244
|
+
console.log("positionAccount:", positionAccount.toBase58())
|
1245
|
+
const params: any = {
|
1246
|
+
price: priceAfterSlippage,
|
1247
|
+
};
|
1248
|
+
|
1249
|
+
let instruction = await this.program.methods
|
1250
|
+
.closePosition(params)
|
1251
|
+
.accounts({
|
1252
|
+
owner: publicKey,
|
1253
|
+
receivingAccount: userReceivingTokenAccount,
|
1254
|
+
transferAuthority: poolConfig.transferAuthority,
|
1255
|
+
perpetuals: poolConfig.perpetuals,
|
1256
|
+
pool: poolConfig.poolAddress,
|
1257
|
+
position: positionAccount,
|
1258
|
+
custody: receivingTokenCustody.custodyAccount,
|
1259
|
+
custodyOracleAccount:
|
1260
|
+
receivingTokenCustody.oracleAddress,
|
1261
|
+
custodyTokenAccount:
|
1262
|
+
receivingTokenCustody.tokenAccount,
|
1263
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
1264
|
+
}).instruction();
|
1265
|
+
instructions.push(instruction)
|
1266
|
+
|
1267
|
+
// SOL is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.
|
1268
|
+
if (receivingTokenSymbol == 'SOL') {
|
1269
|
+
// await closeAccount()
|
1270
|
+
const closeWsolATAIns = createCloseAccountInstruction(userReceivingTokenAccount, publicKey, publicKey);
|
1271
|
+
instructions.push(closeWsolATAIns);
|
1272
|
+
}
|
1273
|
+
} catch (error) {
|
1274
|
+
console.error("perpclient closePosition error:", error);
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
return instructions;
|
1278
|
+
}
|
1279
|
+
|
1280
|
+
// TODO: ATA check - else create - DONE
|
1281
|
+
// TODO: handle SOL wrapping to WSOL and create a ATA - DONE
|
1282
|
+
// TODO : Balance checks - NOT NEEDED
|
1283
|
+
// TODO: for close Accounts - DONE BY ANCHOR
|
1284
|
+
// TODO : if out token WSOL -> unwrap to SOL - DONE
|
1285
|
+
swap = async (
|
1286
|
+
receivingTokenSymbol: string,
|
1287
|
+
dispensingTokenSymbol: string,
|
1288
|
+
amountIn: BN,
|
1289
|
+
minAmountOut: BN,
|
1290
|
+
poolConfig: PoolConfig
|
1291
|
+
): Promise<TransactionInstruction[]> => {
|
1292
|
+
|
1293
|
+
const receivingTokenCustody = poolConfig.custodies.find(
|
1294
|
+
(i) => i.mintKey.toBase58() === poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey.toBase58()
|
1295
|
+
);
|
1296
|
+
if (!receivingTokenCustody) {
|
1297
|
+
throw "receivingTokenCustody not found";
|
1298
|
+
}
|
1299
|
+
const dispensingTokenCustody = poolConfig.custodies.find(
|
1300
|
+
(i) => i.mintKey.toBase58() === poolConfig.getTokenFromSymbol(dispensingTokenSymbol).mintKey.toBase58()
|
1301
|
+
);
|
1302
|
+
if (!dispensingTokenCustody) {
|
1303
|
+
throw "dispensingTokenCustody not found";
|
1304
|
+
}
|
1305
|
+
let publicKey = this.provider.wallet.publicKey;
|
1306
|
+
|
1307
|
+
|
1308
|
+
const instructions = [];
|
1309
|
+
try {
|
1310
|
+
let receivingTokenAccount = await getAssociatedTokenAddress(
|
1311
|
+
receivingTokenCustody.mintKey,
|
1312
|
+
publicKey
|
1313
|
+
);
|
1314
|
+
if (!(await checkIfAccountExists(receivingTokenAccount, this.provider.connection))) {
|
1315
|
+
instructions.push(
|
1316
|
+
createAssociatedTokenAccountInstruction(
|
1317
|
+
publicKey,
|
1318
|
+
receivingTokenAccount,
|
1319
|
+
publicKey,
|
1320
|
+
receivingTokenCustody.mintKey
|
1321
|
+
)
|
1322
|
+
);
|
1323
|
+
}
|
1324
|
+
|
1325
|
+
let dispensingCustodyTokenAccount = await getAssociatedTokenAddress(
|
1326
|
+
dispensingTokenCustody.mintKey,
|
1327
|
+
publicKey
|
1328
|
+
);
|
1329
|
+
if (dispensingTokenSymbol == 'SOL') {
|
1330
|
+
console.log("dispensingTokenSymbol === sol", dispensingTokenSymbol);
|
1331
|
+
const wsolAssociatedTokenAccount = await getAssociatedTokenAddress(
|
1332
|
+
NATIVE_MINT,
|
1333
|
+
publicKey
|
1334
|
+
);
|
1335
|
+
const wsolATAExist = await checkIfAccountExists(wsolAssociatedTokenAccount, this.provider.connection)
|
1336
|
+
if (!wsolATAExist) {
|
1337
|
+
console.log("wsol ata does not exist");
|
1338
|
+
instructions.push(
|
1339
|
+
createAssociatedTokenAccountInstruction(
|
1340
|
+
publicKey,
|
1341
|
+
wsolAssociatedTokenAccount,
|
1342
|
+
publicKey,
|
1343
|
+
NATIVE_MINT
|
1344
|
+
)
|
1345
|
+
);
|
1346
|
+
}
|
1347
|
+
|
1348
|
+
// get balance of WSOL associated token account
|
1349
|
+
const wsolBalance = new BN(wsolATAExist ? (await this.provider.connection.getTokenAccountBalance(wsolAssociatedTokenAccount)).value.amount : 0);
|
1350
|
+
if (wsolBalance.lt(amountIn)) {
|
1351
|
+
// console.log("WSOL balance insufficient");
|
1352
|
+
// so Convert SOL to WSOL
|
1353
|
+
let unWrappedSolBalance = new BN(await this.provider.connection.getBalance(publicKey));
|
1354
|
+
const totalSolBal = unWrappedSolBalance.add(wsolBalance);
|
1355
|
+
if (totalSolBal.lt(amountIn)) {
|
1356
|
+
throw "Insufficient SOL Funds"
|
1357
|
+
}
|
1358
|
+
|
1359
|
+
let conversionAmt = amountIn.sub(wsolBalance);
|
1360
|
+
instructions.push(
|
1361
|
+
SystemProgram.transfer({
|
1362
|
+
fromPubkey: publicKey,
|
1363
|
+
toPubkey: wsolAssociatedTokenAccount,
|
1364
|
+
lamports: conversionAmt.toNumber(), // IS IT SAFE TO PUT AS NUMBER ?
|
1365
|
+
}),
|
1366
|
+
createSyncNativeInstruction(wsolAssociatedTokenAccount)
|
1367
|
+
);
|
1368
|
+
}
|
1369
|
+
} else {
|
1370
|
+
if (!(await checkIfAccountExists(dispensingCustodyTokenAccount, this.provider.connection))) {
|
1371
|
+
throw "Insufficient Funds , Token Account doesn't exist"
|
1372
|
+
}
|
1373
|
+
const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(dispensingCustodyTokenAccount)).value.amount);
|
1374
|
+
if (tokenAccountBalance.lt(amountIn)) {
|
1375
|
+
throw "Insufficient Funds"
|
1376
|
+
}
|
1377
|
+
}
|
1378
|
+
|
1379
|
+
const params = {
|
1380
|
+
amountIn,
|
1381
|
+
minAmountOut,
|
1382
|
+
};
|
1383
|
+
let inx = await this.program.methods
|
1384
|
+
.swap(params)
|
1385
|
+
.accounts({
|
1386
|
+
owner: publicKey,
|
1387
|
+
fundingAccount: dispensingCustodyTokenAccount,
|
1388
|
+
receivingAccount: receivingTokenAccount,
|
1389
|
+
transferAuthority: poolConfig.transferAuthority,
|
1390
|
+
perpetuals: poolConfig.perpetuals,
|
1391
|
+
pool: poolConfig.poolAddress,
|
1392
|
+
|
1393
|
+
receivingCustody: dispensingTokenCustody.custodyAccount,
|
1394
|
+
receivingCustodyOracleAccount: dispensingTokenCustody.oracleAddress,
|
1395
|
+
receivingCustodyTokenAccount: dispensingTokenCustody.tokenAccount,
|
1396
|
+
|
1397
|
+
dispensingCustody: receivingTokenCustody.custodyAccount,
|
1398
|
+
dispensingCustodyOracleAccount: receivingTokenCustody.oracleAddress,
|
1399
|
+
dispensingCustodyTokenAccount: receivingTokenCustody.tokenAccount,
|
1400
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
1401
|
+
})
|
1402
|
+
.instruction();
|
1403
|
+
|
1404
|
+
instructions.push(inx)
|
1405
|
+
|
1406
|
+
// SOL is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.
|
1407
|
+
if (receivingTokenSymbol == 'SOL') {
|
1408
|
+
// await closeAccount()
|
1409
|
+
const closeWsolATAIns = createCloseAccountInstruction(receivingTokenAccount, publicKey, publicKey);
|
1410
|
+
instructions.push(closeWsolATAIns);
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
} catch (err) {
|
1414
|
+
console.log("perpClient Swap error:: ", err);
|
1415
|
+
throw err;
|
1416
|
+
}
|
1417
|
+
|
1418
|
+
return instructions;
|
1419
|
+
}
|
1420
|
+
|
1421
|
+
// TODO: handle SOL wrapping to WSOL and create a ATA - DONE
|
1422
|
+
// TODO :Balance checks - DONE
|
1423
|
+
// TODO: ATA check - else create - DONE
|
1424
|
+
// TODO: for close Accounts - NOT NEEDED
|
1425
|
+
addLiquidity = async (
|
1426
|
+
payTokenSymbol: string,
|
1427
|
+
tokenAmountIn: BN,
|
1428
|
+
minLpAmountOut: BN, // give this value based on slippage
|
1429
|
+
poolConfig: PoolConfig
|
1430
|
+
): Promise<TransactionInstruction[]> => {
|
1431
|
+
|
1432
|
+
const payTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey))!;
|
1433
|
+
if (!payTokenCustody) {
|
1434
|
+
throw "payTokenCustody not found";
|
1435
|
+
}
|
1436
|
+
let publicKey = this.provider.wallet.publicKey;
|
1437
|
+
|
1438
|
+
const instructions = [];
|
1439
|
+
try {
|
1440
|
+
|
1441
|
+
let userPayingTokenAccount = await getAssociatedTokenAddress(
|
1442
|
+
payTokenCustody.mintKey,
|
1443
|
+
publicKey
|
1444
|
+
);
|
1445
|
+
|
1446
|
+
let lpTokenAccount = await getAssociatedTokenAddress(
|
1447
|
+
poolConfig.lpTokenMint,
|
1448
|
+
publicKey
|
1449
|
+
);
|
1450
|
+
|
1451
|
+
let custodyAccountMetas = [];
|
1452
|
+
let custodyOracleAccountMetas = [];
|
1453
|
+
for (const custody of poolConfig.custodies) {
|
1454
|
+
custodyAccountMetas.push({
|
1455
|
+
pubkey: custody.custodyAccount,
|
1456
|
+
isSigner: false,
|
1457
|
+
isWritable: false,
|
1458
|
+
});
|
1459
|
+
|
1460
|
+
custodyOracleAccountMetas.push({
|
1461
|
+
pubkey: custody.oracleAddress,
|
1462
|
+
isSigner: false,
|
1463
|
+
isWritable: false,
|
1464
|
+
});
|
1465
|
+
}
|
1466
|
+
|
1467
|
+
if (!(await checkIfAccountExists(lpTokenAccount, this.provider.connection))) {
|
1468
|
+
instructions.push(
|
1469
|
+
createAssociatedTokenAccountInstruction(
|
1470
|
+
publicKey,
|
1471
|
+
lpTokenAccount,
|
1472
|
+
publicKey,
|
1473
|
+
poolConfig.lpTokenMint
|
1474
|
+
)
|
1475
|
+
);
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
if (payTokenSymbol == 'SOL') {
|
1479
|
+
console.log("payTokenSymbol === sol", payTokenSymbol);
|
1480
|
+
const wsolAssociatedTokenAccount = await getAssociatedTokenAddress(
|
1481
|
+
NATIVE_MINT,
|
1482
|
+
publicKey
|
1483
|
+
);
|
1484
|
+
|
1485
|
+
const wsolATAExist = await checkIfAccountExists(wsolAssociatedTokenAccount, this.provider.connection)
|
1486
|
+
if (!wsolATAExist) {
|
1487
|
+
console.log("wsol ata does not exist");
|
1488
|
+
instructions.push(
|
1489
|
+
createAssociatedTokenAccountInstruction(
|
1490
|
+
publicKey,
|
1491
|
+
wsolAssociatedTokenAccount,
|
1492
|
+
publicKey,
|
1493
|
+
NATIVE_MINT
|
1494
|
+
)
|
1495
|
+
);
|
1496
|
+
}
|
1497
|
+
|
1498
|
+
// get balance of WSOL associated token account
|
1499
|
+
const wsolBalance = new BN(wsolATAExist ? (await this.provider.connection.getTokenAccountBalance(wsolAssociatedTokenAccount)).value.amount : 0);
|
1500
|
+
if (wsolBalance.lt(tokenAmountIn)) {
|
1501
|
+
// console.log("WSOL balance insufficient");
|
1502
|
+
// so Convert SOL to WSOL
|
1503
|
+
let unWrappedSolBalance = new BN(await this.provider.connection.getBalance(publicKey));
|
1504
|
+
const totalSolBal = unWrappedSolBalance.add(wsolBalance);
|
1505
|
+
if (totalSolBal.lt(tokenAmountIn)) {
|
1506
|
+
throw "Insufficient SOL Funds"
|
1507
|
+
}
|
1508
|
+
|
1509
|
+
let conversionAmt = tokenAmountIn.sub(wsolBalance);
|
1510
|
+
instructions.push(
|
1511
|
+
SystemProgram.transfer({
|
1512
|
+
fromPubkey: publicKey,
|
1513
|
+
toPubkey: wsolAssociatedTokenAccount,
|
1514
|
+
lamports: conversionAmt.toNumber(), // IS IT SAFE TO PUT AS NUMBER
|
1515
|
+
}),
|
1516
|
+
createSyncNativeInstruction(wsolAssociatedTokenAccount)
|
1517
|
+
);
|
1518
|
+
}
|
1519
|
+
} else {
|
1520
|
+
if (!(await checkIfAccountExists(userPayingTokenAccount, this.provider.connection))) {
|
1521
|
+
throw "Insufficient Funds , token Account doesn't exist"
|
1522
|
+
}
|
1523
|
+
const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(userPayingTokenAccount)).value.amount);
|
1524
|
+
if (tokenAccountBalance.lt(tokenAmountIn)) {
|
1525
|
+
throw "Insufficient Funds"
|
1526
|
+
}
|
1527
|
+
}
|
1528
|
+
|
1529
|
+
console.log("in add liq", tokenAmountIn);
|
1530
|
+
|
1531
|
+
let inx = await this.program.methods
|
1532
|
+
.addLiquidity({
|
1533
|
+
amountIn: tokenAmountIn,
|
1534
|
+
minLpAmountOut
|
1535
|
+
})
|
1536
|
+
.accounts({
|
1537
|
+
owner: publicKey,
|
1538
|
+
fundingAccount: userPayingTokenAccount, // user token account for custody token account
|
1539
|
+
lpTokenAccount,
|
1540
|
+
transferAuthority: poolConfig.transferAuthority,
|
1541
|
+
perpetuals: poolConfig.perpetuals,
|
1542
|
+
pool: poolConfig.poolAddress,
|
1543
|
+
custody: payTokenCustody.custodyAccount,
|
1544
|
+
custodyOracleAccount: payTokenCustody.oracleAddress,
|
1545
|
+
custodyTokenAccount: payTokenCustody.tokenAccount,
|
1546
|
+
lpTokenMint: poolConfig.lpTokenMint,
|
1547
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
1548
|
+
})
|
1549
|
+
.remainingAccounts([...custodyAccountMetas, ...custodyOracleAccountMetas])
|
1550
|
+
.instruction();
|
1551
|
+
|
1552
|
+
instructions.push(inx)
|
1553
|
+
} catch (err) {
|
1554
|
+
console.log("perpClient addLiquidity error:: ", err);
|
1555
|
+
throw err;
|
1556
|
+
}
|
1557
|
+
|
1558
|
+
return instructions;
|
1559
|
+
}
|
1560
|
+
// TODO: handle SOL wrapping to WSOL and create a ATA - NOT NEEDED
|
1561
|
+
// TODO :Balance checks - DONE
|
1562
|
+
// TODO: ATA check - else create - DONE
|
1563
|
+
// TODO: for LP close Accounts - DONE
|
1564
|
+
// TODO : if out token WSOL -> unwrap to SOL - DONE
|
1565
|
+
removeLiquidity = async (
|
1566
|
+
recieveTokenSymbol: string,
|
1567
|
+
liquidityAmountIn: BN,
|
1568
|
+
minTokenAmountOut: BN, // give this value based on slippage
|
1569
|
+
poolConfig: PoolConfig,
|
1570
|
+
closeLpATA = false
|
1571
|
+
): Promise<TransactionInstruction[]> => {
|
1572
|
+
|
1573
|
+
const recieveTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(recieveTokenSymbol).mintKey))!;
|
1574
|
+
if (!recieveTokenCustody) {
|
1575
|
+
throw "recieveTokenCustody not found";
|
1576
|
+
}
|
1577
|
+
let publicKey = this.provider.wallet.publicKey;
|
1578
|
+
|
1579
|
+
const instructions = [];
|
1580
|
+
try {
|
1581
|
+
let userRecievingTokenAccount = await getAssociatedTokenAddress(
|
1582
|
+
recieveTokenCustody.mintKey,
|
1583
|
+
publicKey
|
1584
|
+
);
|
1585
|
+
|
1586
|
+
if (!(await checkIfAccountExists(userRecievingTokenAccount, this.provider.connection))) {
|
1587
|
+
instructions.push(
|
1588
|
+
createAssociatedTokenAccountInstruction(
|
1589
|
+
publicKey,
|
1590
|
+
userRecievingTokenAccount,
|
1591
|
+
publicKey,
|
1592
|
+
recieveTokenCustody.mintKey
|
1593
|
+
)
|
1594
|
+
);
|
1595
|
+
}
|
1596
|
+
let lpTokenAccount = await getAssociatedTokenAddress(
|
1597
|
+
poolConfig.lpTokenMint,
|
1598
|
+
publicKey
|
1599
|
+
);
|
1600
|
+
|
1601
|
+
let custodyAccountMetas = [];
|
1602
|
+
let custodyOracleAccountMetas = [];
|
1603
|
+
for (const custody of poolConfig.custodies) {
|
1604
|
+
custodyAccountMetas.push({
|
1605
|
+
pubkey: custody.custodyAccount,
|
1606
|
+
isSigner: false,
|
1607
|
+
isWritable: false,
|
1608
|
+
});
|
1609
|
+
|
1610
|
+
custodyOracleAccountMetas.push({
|
1611
|
+
pubkey: custody.oracleAddress,
|
1612
|
+
isSigner: false,
|
1613
|
+
isWritable: false,
|
1614
|
+
});
|
1615
|
+
}
|
1616
|
+
|
1617
|
+
console.log("liquidityAmountIn", liquidityAmountIn.toString());
|
1618
|
+
|
1619
|
+
let removeLiquidityTx = await this.program.methods
|
1620
|
+
.removeLiquidity({
|
1621
|
+
lpAmountIn: liquidityAmountIn,
|
1622
|
+
minAmountOut: minTokenAmountOut
|
1623
|
+
})
|
1624
|
+
.accounts({
|
1625
|
+
owner: publicKey,
|
1626
|
+
receivingAccount: userRecievingTokenAccount, // user token account for custody token account
|
1627
|
+
lpTokenAccount,
|
1628
|
+
transferAuthority: poolConfig.transferAuthority,
|
1629
|
+
perpetuals: poolConfig.perpetuals,
|
1630
|
+
pool: poolConfig.poolAddress,
|
1631
|
+
custody: recieveTokenCustody.custodyAccount,
|
1632
|
+
custodyOracleAccount: recieveTokenCustody.oracleAddress,
|
1633
|
+
custodyTokenAccount: recieveTokenCustody.tokenAccount,
|
1634
|
+
lpTokenMint: poolConfig.lpTokenMint,
|
1635
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
1636
|
+
})
|
1637
|
+
.remainingAccounts([...custodyAccountMetas, ...custodyOracleAccountMetas])
|
1638
|
+
.instruction();
|
1639
|
+
instructions.push(removeLiquidityTx)
|
1640
|
+
|
1641
|
+
if (closeLpATA) {
|
1642
|
+
const closeInx = createCloseAccountInstruction(lpTokenAccount, publicKey, publicKey);
|
1643
|
+
instructions.push(closeInx);
|
1644
|
+
}
|
1645
|
+
|
1646
|
+
// SOL is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.
|
1647
|
+
if (recieveTokenSymbol == 'SOL') {
|
1648
|
+
// await closeAccount()
|
1649
|
+
const closeWsolATAIns = createCloseAccountInstruction(userRecievingTokenAccount, publicKey, publicKey);
|
1650
|
+
instructions.push(closeWsolATAIns);
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
} catch (err) {
|
1654
|
+
console.log("perpClient removeLiquidity error:: ", err);
|
1655
|
+
throw err;
|
1656
|
+
}
|
1657
|
+
|
1658
|
+
return instructions;
|
1659
|
+
}
|
1660
|
+
|
1661
|
+
public async sendTransaction(
|
1662
|
+
ixs: TransactionInstruction[],
|
1663
|
+
opts: any = {},
|
1664
|
+
): Promise<string> {
|
1665
|
+
return await sendTransaction(
|
1666
|
+
this.program.provider as AnchorProvider,
|
1667
|
+
ixs,
|
1668
|
+
opts.alts ?? [],
|
1669
|
+
{
|
1670
|
+
postSendTxCallback: this.postSendTxCallback,
|
1671
|
+
prioritizationFee: this.prioritizationFee,
|
1672
|
+
txConfirmationCommitment: this.txConfirmationCommitment,
|
1673
|
+
...opts,
|
1674
|
+
},
|
1675
|
+
);
|
1676
|
+
}
|
1677
|
+
|
1013
1678
|
}
|
1679
|
+
|
1680
|
+
|