flash-sdk 1.0.15 → 1.0.17

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.
@@ -16,6 +16,7 @@ import {
16
16
  SYSVAR_RENT_PUBKEY,
17
17
  Commitment,
18
18
  LAMPORTS_PER_SOL,
19
+ Signer,
19
20
  } from "@solana/web3.js";
20
21
  import {
21
22
  getAccount,
@@ -25,6 +26,8 @@ import {
25
26
  createSyncNativeInstruction,
26
27
  TOKEN_PROGRAM_ID,
27
28
  NATIVE_MINT,
29
+ createInitializeAccount3Instruction,
30
+ getMinimumBalanceForRentExemptAccount,
28
31
  } from "@solana/spl-token";
29
32
 
30
33
  import { sha256 } from "js-sha256";
@@ -167,7 +170,7 @@ export class PerpetualsClient {
167
170
  };
168
171
 
169
172
  getPool = async (name: string) => {
170
- console.log("pool:", this.getPoolKey(name).toBase58())
173
+ // console.log("pool:", this.getPoolKey(name).toBase58())
171
174
  return this.program.account.pool.fetch(this.getPoolKey(name));
172
175
  };
173
176
 
@@ -211,7 +214,7 @@ export class PerpetualsClient {
211
214
  };
212
215
 
213
216
  getCustody = async (poolName: string, tokenMint: PublicKey) => {
214
- console.log("custody key :", this.getCustodyKey(poolName, tokenMint).toBase58());
217
+ // console.log("custody key :", this.getCustodyKey(poolName, tokenMint).toBase58());
215
218
  return this.program.account.custody.fetch(
216
219
  this.getCustodyKey(poolName, tokenMint)
217
220
  );
@@ -404,7 +407,7 @@ export class PerpetualsClient {
404
407
  } catch (err) {
405
408
  // @ts-ignore
406
409
  if (this.printErrors) {
407
- console.log(err);
410
+ console.error("setAdminSigners err:",err);
408
411
  }
409
412
  throw err;
410
413
  }
@@ -462,8 +465,8 @@ export class PerpetualsClient {
462
465
  borrowRate: BorrowRateParams,
463
466
  ratios: TokenRatios[]
464
467
  ) => {
465
- console.log("CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
466
- console.log("getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
468
+ // console.log("CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
469
+ // console.log("getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
467
470
  try {
468
471
  const trx_id = await this.program.methods
469
472
  // @ts-ignore
@@ -501,7 +504,7 @@ export class PerpetualsClient {
501
504
 
502
505
  console.log("trx_id:", `https://explorer.solana.com/tx/${trx_id}?cluster=devnet`)
503
506
  } catch (error) {
504
- console.log("cli error :", error);
507
+ console.error("cli error :", error);
505
508
  }
506
509
 
507
510
 
@@ -518,8 +521,8 @@ export class PerpetualsClient {
518
521
  borrowRate: BorrowRateParams,
519
522
  ratios: TokenRatios[]
520
523
  ) => {
521
- console.log("CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
522
- console.log("getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
524
+ // console.log("editCustody CustodyKey", this.getCustodyKey(poolName, tokenMint).toBase58())
525
+ // console.log("editCustody getCustodyTokenAccountKey", this.getCustodyTokenAccountKey(poolName, tokenMint).toBase58())
523
526
 
524
527
  const trx_id = await this.program.methods
525
528
  //@ts-ignore
@@ -723,11 +726,10 @@ export class PerpetualsClient {
723
726
  size: BN,
724
727
  side: PositionSide
725
728
  ) => {
726
- console.log("perps: ", this.perpetuals.publicKey.toBase58())
727
-
728
- console.log("poolKey: ", this.getPoolKey(poolName).toBase58())
729
- console.log("custody key : ", this.getCustodyKey(poolName, tokenMint).toBase58());
730
- console.log("orcalve: ", (await this.getCustodyOracleAccountKey(poolName, tokenMint)).toBase58())
729
+ // console.log("perps: ", this.perpetuals.publicKey.toBase58())
730
+ // console.log("poolKey: ", this.getPoolKey(poolName).toBase58())
731
+ // console.log("custody key : ", this.getCustodyKey(poolName, tokenMint).toBase58());
732
+ // console.log("oracle: ", (await this.getCustodyOracleAccountKey(poolName, tokenMint)).toBase58())
731
733
 
732
734
  //@ts-ignore
733
735
  return await this.program.methods
@@ -898,7 +900,7 @@ export class PerpetualsClient {
898
900
  side: PositionSide
899
901
  ) => {
900
902
  const pos = this.getPositionKey(wallet, poolName, tokenMint, side);
901
- console.log("pos:", pos.toBase58())
903
+ // console.log("pos:", pos.toBase58())
902
904
  return await this.program.methods
903
905
  .getPnl({})
904
906
  .accounts({
@@ -926,7 +928,7 @@ export class PerpetualsClient {
926
928
  side: PositionSide
927
929
  ) => {
928
930
  const pos = this.getPositionKey(wallet, poolName, tokenMint, side);
929
- console.log("pos:", pos.toBase58())
931
+ // console.log("pos:", pos.toBase58())
930
932
  return await this.program.methods
931
933
  .getPnl({})
932
934
  .accounts({
@@ -1063,6 +1065,272 @@ export class PerpetualsClient {
1063
1065
  // Create WSOL Token account and not ATA and close it in end
1064
1066
  // TODO: close other Accounts - NOT NEEDED
1065
1067
  openPosition = async (
1068
+ payTokenSymbol: string,
1069
+ priceAfterSlippage: BN,
1070
+ collateralWithfee: BN,
1071
+ fee : BN,
1072
+ size: BN,
1073
+ side: Side,
1074
+ poolConfig: PoolConfig,
1075
+ createUserWSOLATA = true,
1076
+ skipBalanceChecks = false
1077
+ ): Promise< { instructions : TransactionInstruction[] , additionalSigners: Signer[]} > => {
1078
+
1079
+ console.log("open position :::", payTokenSymbol, poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey.toBase58());
1080
+
1081
+ // const slippageMultiplier = isVariant(side, 'long') ? -1 : 1;
1082
+ // const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
1083
+
1084
+ let publicKey = this.provider.wallet.publicKey;
1085
+ const payTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey))!;
1086
+
1087
+ let userCustodyTokenAccount = await getAssociatedTokenAddress(
1088
+ poolConfig.getTokenFromSymbol(payTokenSymbol).mintKey,
1089
+ publicKey
1090
+ );
1091
+
1092
+ let wrappedSolAccount: Keypair | undefined;
1093
+ let preInstructions: TransactionInstruction[] = [];
1094
+ let instructions: TransactionInstruction[] = [];
1095
+ let postInstructions: TransactionInstruction[] = [];
1096
+ const additionalSigners: Signer[] = [];
1097
+
1098
+ try {
1099
+
1100
+ // https://github.com/blockworks-foundation/mango-v4/blob/1ba6513b5ea2b0e557808e712fcf0a811968b45b/ts/client/src/client.ts#L1252
1101
+ // Create WSOL Token account and not ATA and close it in end
1102
+ if (payTokenSymbol == 'SOL' && createUserWSOLATA) {
1103
+ console.log("payTokenSymbol === sol", payTokenSymbol);
1104
+ wrappedSolAccount = new Keypair();
1105
+ const accCreationLamports = (await getMinimumBalanceForRentExemptAccount(this.provider.connection)); // for account creation
1106
+ console.log("accCreationLamports:",accCreationLamports)
1107
+ const lamports = collateralWithfee.add(new BN(accCreationLamports)); // for account creation
1108
+
1109
+ preInstructions = [
1110
+ SystemProgram.createAccount({
1111
+ fromPubkey: publicKey,
1112
+ newAccountPubkey: wrappedSolAccount.publicKey,
1113
+ lamports: lamports.toNumber(), //will this break for large amounts ??
1114
+ space: 165,
1115
+ programId: TOKEN_PROGRAM_ID,
1116
+ }),
1117
+ createInitializeAccount3Instruction(
1118
+ wrappedSolAccount.publicKey,
1119
+ NATIVE_MINT,
1120
+ publicKey,
1121
+ ),
1122
+ ];
1123
+ postInstructions = [
1124
+ createCloseAccountInstruction(
1125
+ wrappedSolAccount.publicKey,
1126
+ publicKey,
1127
+ publicKey,
1128
+ ),
1129
+ ];
1130
+ additionalSigners.push(wrappedSolAccount);
1131
+
1132
+ } else if(createUserWSOLATA == false){
1133
+ console.log("skip WSOL checks and creation ,since createUserWSOLATA == false")
1134
+ } else {
1135
+ // for other tokens check if ATA and balance
1136
+ if (!(await checkIfAccountExists(userCustodyTokenAccount, this.provider.connection))) {
1137
+ throw "Insufficient Funds , token Account doesn't exist"
1138
+ }
1139
+
1140
+ if(!skipBalanceChecks){
1141
+ const tokenAccountBalance = new BN((await this.provider.connection.getTokenAccountBalance(userCustodyTokenAccount)).value.amount);
1142
+ if (tokenAccountBalance.lt(collateralWithfee)) {
1143
+ throw `Insufficient Funds need more ${collateralWithfee.sub(tokenAccountBalance)} tokens`
1144
+ }
1145
+ }
1146
+
1147
+ }
1148
+
1149
+ // replace with getPositionKey()
1150
+ let positionAccount = PublicKey.findProgramAddressSync(
1151
+ [
1152
+ Buffer.from("position"),
1153
+ publicKey.toBuffer(),
1154
+ poolConfig.poolAddress.toBuffer(),
1155
+ payTokenCustody.custodyAccount.toBuffer(),
1156
+ isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
1157
+ ],
1158
+ this.programId
1159
+ )[0];
1160
+
1161
+ const params: any = {
1162
+ price: priceAfterSlippage,
1163
+ collateral : collateralWithfee,
1164
+ size,
1165
+ side,
1166
+ };
1167
+
1168
+ let instruction = await this.program.methods
1169
+ .openPosition(params)
1170
+ .accounts({
1171
+ owner: publicKey,
1172
+ fundingAccount: payTokenSymbol == 'SOL' ? wrappedSolAccount.publicKey : userCustodyTokenAccount,
1173
+ transferAuthority: poolConfig.transferAuthority,
1174
+ perpetuals: poolConfig.perpetuals,
1175
+ pool: poolConfig.poolAddress,
1176
+ position: positionAccount,
1177
+ custody: payTokenCustody.custodyAccount,
1178
+ custodyOracleAccount:
1179
+ payTokenCustody.oracleAddress,
1180
+ custodyTokenAccount:
1181
+ payTokenCustody.tokenAccount,
1182
+ systemProgram: SystemProgram.programId,
1183
+ tokenProgram: TOKEN_PROGRAM_ID,
1184
+ }).instruction()
1185
+
1186
+
1187
+ instructions.push(instruction);
1188
+
1189
+ } catch (error) {
1190
+ console.log("perpClient openPosition error:", error)
1191
+ }
1192
+ return {
1193
+ instructions : [...preInstructions, ...instructions ,...postInstructions],
1194
+ additionalSigners
1195
+ };
1196
+ }
1197
+
1198
+ // TODO: handle SOL wrapping to WSOL and create a ATA - NOT NEEDED
1199
+ // TODO : Balance checks - NOT NEEDED
1200
+ // TODO: ATA check - else create - DONE
1201
+ // TODO: for close Accounts - DONE BY ANCHOR
1202
+ // TODO : if out token WSOL -> unwrap to SOL - DONE
1203
+ closePosition = async (
1204
+ receivingTokenSymbol: string,
1205
+ priceAfterSlippage: BN,
1206
+ side: Side,
1207
+ poolConfig: PoolConfig,
1208
+ createUserATA = true,
1209
+ closeUsersWSOLATA = false // to get back WSOL=>SOL
1210
+ ): Promise< { instructions : TransactionInstruction[] , additionalSigners: Signer[]}> => {
1211
+
1212
+ console.log("close position :::", receivingTokenSymbol, poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey.toBase58());
1213
+
1214
+ // opp during close
1215
+ // const slippageMultiplier = isVariant(side, 'short') ? -1 : 1;
1216
+ // const priceAfterSlippage = price.mul(new BN((100 - (slippagePercentage * slippageMultiplier)) * 100)).div(new BN(100 * 100))
1217
+
1218
+ let publicKey = this.provider.wallet.publicKey;
1219
+
1220
+ let userReceivingTokenAccount : PublicKey;
1221
+ let wrappedSolAccount: Keypair | undefined;
1222
+ let preInstructions: TransactionInstruction[] = [];
1223
+ let instructions: TransactionInstruction[] = [];
1224
+ let postInstructions: TransactionInstruction[] = [];
1225
+ const additionalSigners: Signer[] = [];
1226
+ try {
1227
+
1228
+ if (receivingTokenSymbol == 'SOL') {
1229
+ wrappedSolAccount = new Keypair();
1230
+ userReceivingTokenAccount = wrappedSolAccount.publicKey;
1231
+ const lamports = (await getMinimumBalanceForRentExemptAccount(this.provider.connection)); // for account creation
1232
+
1233
+ preInstructions = [
1234
+ SystemProgram.createAccount({
1235
+ fromPubkey: publicKey,
1236
+ newAccountPubkey: wrappedSolAccount.publicKey,
1237
+ lamports: lamports, //will this break for large amounts ??
1238
+ space: 165,
1239
+ programId: TOKEN_PROGRAM_ID,
1240
+ }),
1241
+ createInitializeAccount3Instruction(
1242
+ wrappedSolAccount.publicKey,
1243
+ NATIVE_MINT,
1244
+ publicKey,
1245
+ ),
1246
+ ];
1247
+ postInstructions = [
1248
+ createCloseAccountInstruction(
1249
+ wrappedSolAccount.publicKey,
1250
+ publicKey,
1251
+ publicKey,
1252
+ ),
1253
+ ];
1254
+ additionalSigners.push(wrappedSolAccount);
1255
+ } else {
1256
+
1257
+ userReceivingTokenAccount = await getAssociatedTokenAddress(
1258
+ poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey,
1259
+ publicKey
1260
+ );
1261
+
1262
+ if (createUserATA && !(await checkIfAccountExists(userReceivingTokenAccount, this.provider.connection))) {
1263
+ preInstructions.push(
1264
+ createAssociatedTokenAccountInstruction(
1265
+ publicKey,
1266
+ userReceivingTokenAccount,
1267
+ publicKey,
1268
+ poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey
1269
+ )
1270
+ );
1271
+ }
1272
+
1273
+ }
1274
+
1275
+
1276
+ const receivingTokenCustody = poolConfig.custodies.find(i => i.mintKey.equals(poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey))!;
1277
+
1278
+ // replace with getPositionKey
1279
+ let positionAccount = PublicKey.findProgramAddressSync(
1280
+ [
1281
+ Buffer.from("position"),
1282
+ publicKey.toBuffer(),
1283
+ poolConfig.poolAddress.toBuffer(),
1284
+ receivingTokenCustody.custodyAccount.toBuffer(),
1285
+ isVariant(side, 'long') ? Buffer.from([1]) : Buffer.from([2]),
1286
+ ],
1287
+ this.programId
1288
+ )[0];
1289
+
1290
+ // console.log("positionAccount:", positionAccount.toBase58())
1291
+ const params: any = {
1292
+ price: priceAfterSlippage,
1293
+ };
1294
+
1295
+ let instruction = await this.program.methods
1296
+ .closePosition(params)
1297
+ .accounts({
1298
+ owner: publicKey,
1299
+ receivingAccount: userReceivingTokenAccount,
1300
+ transferAuthority: poolConfig.transferAuthority,
1301
+ perpetuals: poolConfig.perpetuals,
1302
+ pool: poolConfig.poolAddress,
1303
+ position: positionAccount,
1304
+ custody: receivingTokenCustody.custodyAccount,
1305
+ custodyOracleAccount:
1306
+ receivingTokenCustody.oracleAddress,
1307
+ custodyTokenAccount:
1308
+ receivingTokenCustody.tokenAccount,
1309
+ tokenProgram: TOKEN_PROGRAM_ID,
1310
+ }).instruction();
1311
+ instructions.push(instruction)
1312
+
1313
+ if (receivingTokenSymbol == 'WSOL' && closeUsersWSOLATA) {
1314
+ const closeWsolATAIns = createCloseAccountInstruction(userReceivingTokenAccount, publicKey, publicKey);
1315
+ postInstructions.push(closeWsolATAIns);
1316
+ }
1317
+ } catch (error) {
1318
+ console.error("perpclient closePosition error:", error);
1319
+ }
1320
+
1321
+ return {
1322
+ instructions : [...preInstructions, ...instructions ,...postInstructions],
1323
+ additionalSigners
1324
+ };
1325
+ }
1326
+
1327
+
1328
+ // ==== OLD
1329
+ // TODO: handle SOL wrapping to WSOL and create a ATA - DONE
1330
+ // TODO: Balance checks - DONE
1331
+ // TODO: ATA check - else create - DONE
1332
+ // TODO: for close Accounts - NOT NEEDED
1333
+ openPositionOld = async (
1066
1334
  payTokenSymbol: string,
1067
1335
  priceAfterSlippage: BN,
1068
1336
  collateral: BN,
@@ -1089,11 +1357,13 @@ export class PerpetualsClient {
1089
1357
  const instructions = [];
1090
1358
  try {
1091
1359
 
1092
- // https://github.com/blockworks-foundation/mango-v4/blob/1ba6513b5ea2b0e557808e712fcf0a811968b45b/ts/client/src/client.ts#L1252
1093
- // Create WSOL Token account and not ATA and close it in end
1094
1360
  if (payTokenSymbol == 'SOL' && createUserWSOLATA) {
1095
1361
  console.log("payTokenSymbol === sol", payTokenSymbol);
1096
1362
  const wsolAssociatedTokenAccount = userCustodyTokenAccount;
1363
+ // await getAssociatedTokenAddress(
1364
+ // NATIVE_MINT,
1365
+ // publicKey
1366
+ // );
1097
1367
  const wsolATAExist = await checkIfAccountExists(wsolAssociatedTokenAccount, this.provider.connection)
1098
1368
  if (!wsolATAExist) {
1099
1369
  console.log("wsol ata does not exist");
@@ -1192,17 +1462,17 @@ export class PerpetualsClient {
1192
1462
  return instructions;
1193
1463
  }
1194
1464
 
1465
+ // ==== OLD
1195
1466
  // TODO: handle SOL wrapping to WSOL and create a ATA - NOT NEEDED
1196
1467
  // TODO : Balance checks - NOT NEEDED
1197
1468
  // TODO: ATA check - else create - DONE
1198
1469
  // TODO: for close Accounts - DONE BY ANCHOR
1199
1470
  // TODO : if out token WSOL -> unwrap to SOL - DONE
1200
- closePosition = async (
1471
+ closePositionOld = async (
1201
1472
  receivingTokenSymbol: string,
1202
1473
  priceAfterSlippage: BN,
1203
1474
  side: Side,
1204
- poolConfig: PoolConfig,
1205
- closeUsersWSOLATA = false // to get back WSOL=>SOL
1475
+ poolConfig: PoolConfig
1206
1476
  ): Promise<TransactionInstruction[]> => {
1207
1477
 
1208
1478
  console.log("close position :::", receivingTokenSymbol, poolConfig.getTokenFromSymbol(receivingTokenSymbol).mintKey.toBase58());
@@ -1269,7 +1539,7 @@ export class PerpetualsClient {
1269
1539
  instructions.push(instruction)
1270
1540
 
1271
1541
  // SOL is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.
1272
- if (receivingTokenSymbol == 'SOL' && closeUsersWSOLATA) {
1542
+ if (receivingTokenSymbol == 'SOL') {
1273
1543
  // await closeAccount()
1274
1544
  const closeWsolATAIns = createCloseAccountInstruction(userReceivingTokenAccount, publicKey, publicKey);
1275
1545
  instructions.push(closeWsolATAIns);
@@ -1281,6 +1551,8 @@ export class PerpetualsClient {
1281
1551
  return instructions;
1282
1552
  }
1283
1553
 
1554
+
1555
+
1284
1556
  // TODO: ATA check - else create - DONE
1285
1557
  // TODO: handle SOL wrapping to WSOL and create a ATA - DONE
1286
1558
  // TODO : Balance checks - NOT NEEDED
@@ -1420,7 +1692,7 @@ export class PerpetualsClient {
1420
1692
  }
1421
1693
 
1422
1694
  } catch (err) {
1423
- console.log("perpClient Swap error:: ", err);
1695
+ console.error("perpClient Swap error:: ", err);
1424
1696
  throw err;
1425
1697
  }
1426
1698
 
package/src/PoolConfig.ts CHANGED
@@ -83,14 +83,14 @@ export class PoolConfig {
83
83
  // return poolConfigs.pools.map(p => this.fromIdsByName(p.poolName, cluster))
84
84
  // }
85
85
 
86
- static getCustodyConfig(custodyAccountPk: Address, poolName: string, cluster: Cluster) {
86
+ static getCustodyConfig(custodyAccountPk: Address, poolName: string, cluster: Cluster) : CustodyConfig {
87
87
  return this.fromIdsByName(poolName, cluster).custodies.find(f => f.custodyAccount.toBase58() === custodyAccountPk.toString())
88
88
  }
89
89
 
90
90
  static getTokensInPool(name: string, cluster: Cluster): Token[] {
91
91
  const poolConfig = poolConfigs.pools.find((pool) => pool['poolName'] === name && cluster === pool['cluster']);
92
92
  if (!poolConfig) throw new Error(`No pool config ${name} found in Ids!`);
93
- const tokens = poolConfig['tokens'].map(i => {
93
+ const tokens :Token[] = poolConfig['tokens'].map(i => {
94
94
  return {
95
95
  ...i,
96
96
  mintKey: new PublicKey(i.mintKey)
@@ -102,13 +102,13 @@ export class PoolConfig {
102
102
  static fromIdsByName(name: string, cluster: Cluster): PoolConfig {
103
103
  const poolConfig = poolConfigs.pools.find((pool) => pool['poolName'] === name && cluster === pool['cluster']);
104
104
  if (!poolConfig) throw new Error(`No pool config ${name} found in Ids!`);
105
- const tokens = poolConfig['tokens'].map(i => {
105
+ const tokens:Token[] = poolConfig['tokens'].map(i => {
106
106
  return {
107
107
  ...i,
108
108
  mintKey : new PublicKey(i.mintKey)
109
109
  }
110
110
  })
111
- const custodies = poolConfig['custodies'].map(i => {
111
+ const custodies : CustodyConfig[] = poolConfig['custodies'].map(i => {
112
112
  return {
113
113
  ...i,
114
114
  custodyAccount : new PublicKey(i.custodyAccount),
@@ -139,13 +139,13 @@ export class PoolConfig {
139
139
  if (!poolConfig)
140
140
  throw new Error(`No pool config ${poolPk.toString()} found in Ids!`);
141
141
 
142
- const tokens = poolConfig['tokens'].map(i => {
142
+ const tokens :Token[] = poolConfig['tokens'].map(i => {
143
143
  return {
144
144
  ...i,
145
145
  mintKey : new PublicKey(i.mintKey)
146
146
  }
147
147
  })
148
- const custodies = poolConfig['custodies'].map(i => {
148
+ const custodies : CustodyConfig[] = poolConfig['custodies'].map(i => {
149
149
  return {
150
150
  ...i,
151
151
  custodyAccount : new PublicKey(i.custodyAccount),