@atomiqlabs/chain-solana 7.3.8 → 8.0.0-beta.0

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 (57) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/solana/SolanaChains.d.ts +14 -0
  4. package/dist/solana/SolanaChains.js +18 -0
  5. package/dist/solana/SolanaInitializer.d.ts +18 -0
  6. package/dist/solana/SolanaInitializer.js +59 -0
  7. package/dist/solana/base/SolanaAction.js +25 -38
  8. package/dist/solana/base/modules/SolanaBlocks.js +18 -29
  9. package/dist/solana/base/modules/SolanaEvents.js +15 -26
  10. package/dist/solana/base/modules/SolanaFees.d.ts +4 -5
  11. package/dist/solana/base/modules/SolanaFees.js +168 -182
  12. package/dist/solana/base/modules/SolanaSlots.js +16 -29
  13. package/dist/solana/base/modules/SolanaTokens.d.ts +6 -7
  14. package/dist/solana/base/modules/SolanaTokens.js +63 -84
  15. package/dist/solana/base/modules/SolanaTransactions.d.ts +2 -2
  16. package/dist/solana/base/modules/SolanaTransactions.js +143 -165
  17. package/dist/solana/btcrelay/SolanaBtcRelay.d.ts +2 -3
  18. package/dist/solana/btcrelay/SolanaBtcRelay.js +185 -221
  19. package/dist/solana/events/SolanaChainEvents.js +113 -138
  20. package/dist/solana/events/SolanaChainEventsBrowser.js +56 -65
  21. package/dist/solana/program/modules/SolanaProgramEvents.js +13 -24
  22. package/dist/solana/swaps/SolanaSwapData.d.ts +15 -11
  23. package/dist/solana/swaps/SolanaSwapData.js +29 -13
  24. package/dist/solana/swaps/SolanaSwapProgram.d.ts +40 -41
  25. package/dist/solana/swaps/SolanaSwapProgram.js +212 -221
  26. package/dist/solana/swaps/modules/SolanaDataAccount.d.ts +2 -3
  27. package/dist/solana/swaps/modules/SolanaDataAccount.js +117 -141
  28. package/dist/solana/swaps/modules/SolanaLpVault.d.ts +4 -5
  29. package/dist/solana/swaps/modules/SolanaLpVault.js +87 -110
  30. package/dist/solana/swaps/modules/SwapClaim.d.ts +4 -4
  31. package/dist/solana/swaps/modules/SwapClaim.js +122 -134
  32. package/dist/solana/swaps/modules/SwapInit.d.ts +2 -3
  33. package/dist/solana/swaps/modules/SwapInit.js +254 -285
  34. package/dist/solana/swaps/modules/SwapRefund.d.ts +2 -3
  35. package/dist/solana/swaps/modules/SwapRefund.js +103 -113
  36. package/dist/utils/Utils.d.ts +10 -0
  37. package/dist/utils/Utils.js +62 -35
  38. package/package.json +9 -6
  39. package/src/index.ts +1 -0
  40. package/src/solana/SolanaChains.ts +16 -0
  41. package/src/solana/SolanaInitializer.ts +98 -0
  42. package/src/solana/base/SolanaBase.ts +1 -2
  43. package/src/solana/base/modules/SolanaEvents.ts +0 -1
  44. package/src/solana/base/modules/SolanaFees.ts +35 -31
  45. package/src/solana/base/modules/SolanaTokens.ts +26 -27
  46. package/src/solana/base/modules/SolanaTransactions.ts +33 -28
  47. package/src/solana/btcrelay/SolanaBtcRelay.ts +6 -10
  48. package/src/solana/events/SolanaChainEventsBrowser.ts +14 -10
  49. package/src/solana/program/modules/SolanaProgramEvents.ts +1 -1
  50. package/src/solana/swaps/SolanaSwapData.ts +38 -19
  51. package/src/solana/swaps/SolanaSwapProgram.ts +133 -105
  52. package/src/solana/swaps/modules/SolanaDataAccount.ts +4 -6
  53. package/src/solana/swaps/modules/SolanaLpVault.ts +18 -18
  54. package/src/solana/swaps/modules/SwapClaim.ts +14 -17
  55. package/src/solana/swaps/modules/SwapInit.ts +35 -38
  56. package/src/solana/swaps/modules/SwapRefund.ts +20 -23
  57. package/src/utils/Utils.ts +35 -0
@@ -1,4 +1,3 @@
1
- import * as BN from "bn.js";
2
1
  import {
3
2
  ComputeBudgetProgram,
4
3
  Connection,
@@ -16,26 +15,26 @@ const MAX_FEE_AGE = 5000;
16
15
  export type FeeBribeData = {
17
16
  address: string,
18
17
  endpoint: string,
19
- getBribeFee?: (original: BN) => BN
18
+ getBribeFee?: (original: bigint) => bigint
20
19
  };
21
20
 
22
21
  export class SolanaFees {
23
22
 
24
23
  private readonly connection: Connection;
25
- private readonly maxFeeMicroLamports: BN;
24
+ private readonly maxFeeMicroLamports: bigint;
26
25
  private readonly numSamples: number;
27
26
  private readonly period: number;
28
27
  private useHeliusApi: "yes" | "no" | "auto";
29
28
  private heliusApiSupported: boolean = true;
30
29
  private readonly heliusFeeLevel: "min" | "low" | "medium" | "high" | "veryHigh" | "unsafeMax";
31
30
  private readonly bribeData?: FeeBribeData;
32
- private readonly getStaticFee?: (original: BN) => BN;
31
+ private readonly getStaticFee?: (original: bigint) => bigint;
33
32
 
34
33
  private readonly logger = getLogger("SolanaFees: ");
35
34
 
36
35
  private blockFeeCache: {
37
36
  timestamp: number,
38
- feeRate: Promise<BN>
37
+ feeRate: Promise<bigint>
39
38
  } = null;
40
39
 
41
40
  constructor(
@@ -45,11 +44,11 @@ export class SolanaFees {
45
44
  period: number = 150,
46
45
  useHeliusApi: "yes" | "no" | "auto" = "auto",
47
46
  heliusFeeLevel: "min" | "low" | "medium" | "high" | "veryHigh" | "unsafeMax" = "veryHigh",
48
- getStaticFee?: (feeRate: BN) => BN,
47
+ getStaticFee?: (feeRate: bigint) => bigint,
49
48
  bribeData?: FeeBribeData,
50
49
  ) {
51
50
  this.connection = connection;
52
- this.maxFeeMicroLamports = new BN(maxFeeMicroLamports);
51
+ this.maxFeeMicroLamports = BigInt(maxFeeMicroLamports);
53
52
  this.numSamples = numSamples;
54
53
  this.period = period;
55
54
  this.useHeliusApi = useHeliusApi;
@@ -172,7 +171,7 @@ export class SolanaFees {
172
171
  * @param parsedTx
173
172
  * @private
174
173
  */
175
- private getJitoTxFee(parsedTx: Transaction): BN | null {
174
+ private getJitoTxFee(parsedTx: Transaction): bigint | null {
176
175
  const lastIx = parsedTx.instructions[parsedTx.instructions.length-1];
177
176
 
178
177
  if(!lastIx.programId.equals(SystemProgram.programId)) return null;
@@ -180,7 +179,7 @@ export class SolanaFees {
180
179
 
181
180
  const decodedIxData = SystemInstruction.decodeTransfer(lastIx);
182
181
  if(decodedIxData.toPubkey.toBase58()!==this.bribeData?.address) return null;
183
- return new BN(decodedIxData.lamports.toString(10));
182
+ return decodedIxData.lamports;
184
183
  }
185
184
 
186
185
  /**
@@ -189,21 +188,21 @@ export class SolanaFees {
189
188
  * @param slot
190
189
  * @private
191
190
  */
192
- private async getBlockMeanFeeRate(slot: number): Promise<BN | null> {
191
+ private async getBlockMeanFeeRate(slot: number): Promise<bigint | null> {
193
192
  const block = await this.getBlockWithSignature(slot);
194
193
  if(block==null) return null;
195
194
 
196
195
  const blockComission = block.rewards.find(e => e.rewardType==="Fee");
197
- const totalBlockFees = new BN(blockComission.lamports).mul(new BN(2));
196
+ const totalBlockFees: bigint = BigInt(blockComission.lamports) * 2n;
198
197
 
199
198
  //Subtract per-signature fees to get pure compute fees
200
- const totalTransactionBaseFees = new BN(block.signatures.length).mul(new BN(5000));
201
- const computeFees = totalBlockFees.sub(totalTransactionBaseFees);
199
+ const totalTransactionBaseFees = BigInt(block.signatures.length) * 5000n;
200
+ const computeFees = totalBlockFees - totalTransactionBaseFees;
202
201
 
203
202
  //Total compute fees in micro lamports
204
- const computeFeesMicroLamports = computeFees.mul(new BN(1000000));
203
+ const computeFeesMicroLamports = computeFees * 1000000n;
205
204
  //micro lamports per CU considering block was full (48M compute units)
206
- const perCUMicroLamports = computeFeesMicroLamports.div(new BN(48000000));
205
+ const perCUMicroLamports = computeFeesMicroLamports / 48000000n;
207
206
 
208
207
  this.logger.debug("getBlockMeanFeeRate(): slot: "+slot+" total reward: "+totalBlockFees.toString(10)+
209
208
  " total transactions: "+block.signatures.length+" computed fee: "+perCUMicroLamports);
@@ -217,7 +216,7 @@ export class SolanaFees {
217
216
  * @private
218
217
  * @returns {Promise<BN>} sampled mean microLamports/CU fee over the last period
219
218
  */
220
- private async _getGlobalFeeRate(): Promise<BN> {
219
+ private async _getGlobalFeeRate(): Promise<bigint> {
221
220
  let slot = await this.connection.getSlot();
222
221
 
223
222
  const slots: number[] = [];
@@ -226,10 +225,10 @@ export class SolanaFees {
226
225
  slots.push(slot-i);
227
226
  }
228
227
 
229
- const promises: Promise<BN>[] = [];
228
+ const promises: Promise<bigint>[] = [];
230
229
  for(let i=0;i<this.numSamples;i++) {
231
230
  promises.push((async () => {
232
- let feeRate: BN = null;
231
+ let feeRate: bigint = null;
233
232
  while(feeRate==null) {
234
233
  if(slots.length===0) throw new Error("Ran out of slots to check!");
235
234
  const index = Math.floor(Math.random()*slots.length);
@@ -244,7 +243,7 @@ export class SolanaFees {
244
243
  const meanFees = await Promise.all(promises);
245
244
 
246
245
  let min = null;
247
- meanFees.forEach(e => min==null ? min = e : min = BN.min(min, e));
246
+ meanFees.forEach(e => min==null || min > e ? min = e : 0);
248
247
 
249
248
  if(min!=null) this.logger.debug("_getGlobalFeeRate(): slot: "+slot+" global fee minimum: "+min.toString(10));
250
249
 
@@ -257,13 +256,15 @@ export class SolanaFees {
257
256
  * @param mutableAccounts
258
257
  * @private
259
258
  */
260
- private async _getFeeRate(mutableAccounts: PublicKey[]): Promise<BN> {
259
+ private async _getFeeRate(mutableAccounts: PublicKey[]): Promise<bigint> {
261
260
  if(this.useHeliusApi==="yes" || (this.useHeliusApi==="auto" && this.heliusApiSupported)) {
262
261
  //Try to use getPriorityFeeEstimate api of Helius
263
262
  const fees = await this.getPriorityFeeEstimate(mutableAccounts);
264
263
  if(fees!=null) {
265
- const calculatedFee = BN.max(new BN(8000), new BN(fees[this.heliusFeeLevel]));
266
- return BN.min(calculatedFee, this.maxFeeMicroLamports);
264
+ let calculatedFee = BigInt(fees[this.heliusFeeLevel]);
265
+ if(calculatedFee < 8000n) calculatedFee = 8000n;
266
+ if(calculatedFee > this.maxFeeMicroLamports) calculatedFee = this.maxFeeMicroLamports;
267
+ return calculatedFee;
267
268
  }
268
269
  this.logger.warn("_getFeeRate(): tried fetching fees from Helius API, not supported," +
269
270
  " falling back to client-side fee estimation");
@@ -280,13 +281,16 @@ export class SolanaFees {
280
281
  const data = resp[resp.length-i-1];
281
282
  if(data!=null) lamports = Math.min(lamports, data.prioritizationFee);
282
283
  }
283
- return new BN(lamports);
284
+ return BigInt(lamports);
284
285
  })
285
286
  ]);
286
287
 
287
- const fee = BN.max(BN.max(globalFeeRate, localFeeRate), new BN(8000));
288
+ let fee = globalFeeRate;
289
+ if(fee < localFeeRate) fee = localFeeRate;
290
+ if(fee < 8000n) fee = 8000n;
291
+ if(fee > this.maxFeeMicroLamports) fee = this.maxFeeMicroLamports;
288
292
 
289
- return BN.min(fee, this.maxFeeMicroLamports);
293
+ return fee;
290
294
  }
291
295
 
292
296
  /**
@@ -294,7 +298,7 @@ export class SolanaFees {
294
298
  *
295
299
  * @returns {Promise<BN>} global fee rate microLamports/CU
296
300
  */
297
- public getGlobalFeeRate(): Promise<BN> {
301
+ public getGlobalFeeRate(): Promise<bigint> {
298
302
  if(this.blockFeeCache==null || Date.now() - this.blockFeeCache.timestamp > MAX_FEE_AGE) {
299
303
  let obj = {
300
304
  timestamp: Date.now(),
@@ -344,8 +348,8 @@ export class SolanaFees {
344
348
  * @param feeRate
345
349
  * @param includeStaticFee whether the include the static/base part of the fee rate
346
350
  */
347
- public getPriorityFee(computeUnits: number, feeRate: string, includeStaticFee: boolean = true): BN {
348
- if(feeRate==null) return new BN(0);
351
+ public getPriorityFee(computeUnits: number, feeRate: string, includeStaticFee: boolean = true): bigint {
352
+ if(feeRate==null) return 0n;
349
353
 
350
354
  const hashArr = feeRate.split("#");
351
355
  if(hashArr.length>1) {
@@ -353,10 +357,10 @@ export class SolanaFees {
353
357
  }
354
358
 
355
359
  const arr = feeRate.split(";");
356
- const cuPrice = new BN(arr[0]);
357
- const staticFee = includeStaticFee ? new BN(arr[1]) : new BN(0);
360
+ const cuPrice = BigInt(arr[0]);
361
+ const staticFee = includeStaticFee ? BigInt(arr[1]) : 0n;
358
362
 
359
- return staticFee.add(cuPrice.mul(new BN(computeUnits)).div(new BN(1000000)));
363
+ return staticFee + (cuPrice * BigInt(computeUnits) / 1000000n);
360
364
  }
361
365
 
362
366
  /**
@@ -6,7 +6,6 @@ import {
6
6
  getAccount, getAssociatedTokenAddressSync,
7
7
  TokenAccountNotFoundError
8
8
  } from "@solana/spl-token";
9
- import * as BN from "bn.js";
10
9
  import {SolanaTx} from "./SolanaTransactions";
11
10
  import {SolanaAction} from "../SolanaAction";
12
11
  import {tryWithRetries} from "../../../utils/Utils";
@@ -55,18 +54,18 @@ export class SolanaTokens extends SolanaModule {
55
54
  * @param initAta whether we should also initialize the ATA before depositing SOL
56
55
  * @constructor
57
56
  */
58
- public Wrap(publicKey: PublicKey, amount: BN, initAta: boolean): SolanaAction {
59
- const ata = getAssociatedTokenAddressSync(this.WSOL_ADDRESS, publicKey, true);
57
+ public Wrap(publicKey: PublicKey, amount: bigint, initAta: boolean): SolanaAction {
58
+ const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
60
59
  const action = new SolanaAction(publicKey, this.root);
61
60
  if(initAta) action.addIx(
62
- createAssociatedTokenAccountInstruction(publicKey, ata, publicKey, this.WSOL_ADDRESS),
61
+ createAssociatedTokenAccountInstruction(publicKey, ata, publicKey, SolanaTokens.WSOL_ADDRESS),
63
62
  SolanaTokens.CUCosts.ATA_INIT
64
63
  );
65
64
  action.addIx(
66
65
  SystemProgram.transfer({
67
66
  fromPubkey: publicKey,
68
67
  toPubkey: ata,
69
- lamports: BigInt(amount.toString(10))
68
+ lamports: amount
70
69
  }),
71
70
  SolanaTokens.CUCosts.WRAP_SOL
72
71
  );
@@ -81,7 +80,7 @@ export class SolanaTokens extends SolanaModule {
81
80
  * @constructor
82
81
  */
83
82
  public Unwrap(publicKey: PublicKey): SolanaAction {
84
- const ata = getAssociatedTokenAddressSync(this.WSOL_ADDRESS, publicKey, true);
83
+ const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
85
84
  return new SolanaAction(
86
85
  publicKey,
87
86
  this.root,
@@ -90,8 +89,8 @@ export class SolanaTokens extends SolanaModule {
90
89
  );
91
90
  }
92
91
 
93
- public readonly WSOL_ADDRESS = new PublicKey("So11111111111111111111111111111111111111112");
94
- public readonly SPL_ATA_RENT_EXEMPT = 2039280;
92
+ public static readonly WSOL_ADDRESS = new PublicKey("So11111111111111111111111111111111111111112");
93
+ public static readonly SPL_ATA_RENT_EXEMPT = 2039280;
95
94
 
96
95
  /**
97
96
  * Action for transferring the native SOL token, uses provider's public key as a sender
@@ -102,12 +101,12 @@ export class SolanaTokens extends SolanaModule {
102
101
  * @constructor
103
102
  * @private
104
103
  */
105
- private SolTransfer(signer: PublicKey, recipient: PublicKey, amount: BN): SolanaAction {
104
+ private SolTransfer(signer: PublicKey, recipient: PublicKey, amount: bigint): SolanaAction {
106
105
  return new SolanaAction(signer, this.root,
107
106
  SystemProgram.transfer({
108
107
  fromPubkey: signer,
109
108
  toPubkey: recipient,
110
- lamports: BigInt(amount.toString(10))
109
+ lamports: amount
111
110
  }),
112
111
  SolanaTokens.CUCosts.TRANSFER_SOL
113
112
  );
@@ -123,7 +122,7 @@ export class SolanaTokens extends SolanaModule {
123
122
  * @constructor
124
123
  * @private
125
124
  */
126
- private Transfer(signer: PublicKey, recipient: PublicKey, token: PublicKey, amount: BN): SolanaAction {
125
+ private Transfer(signer: PublicKey, recipient: PublicKey, token: PublicKey, amount: bigint): SolanaAction {
127
126
  const srcAta = getAssociatedTokenAddressSync(token, signer, true)
128
127
  const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
129
128
  return new SolanaAction(signer, this.root,
@@ -131,7 +130,7 @@ export class SolanaTokens extends SolanaModule {
131
130
  srcAta,
132
131
  dstAta,
133
132
  signer,
134
- BigInt(amount.toString(10))
133
+ amount
135
134
  ),
136
135
  SolanaTokens.CUCosts.TRANSFER
137
136
  );
@@ -146,8 +145,8 @@ export class SolanaTokens extends SolanaModule {
146
145
  * @param feeRate fee rate to use for the transactions
147
146
  * @private
148
147
  */
149
- private async txsTransferSol(signer: PublicKey, amount: BN, recipient: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
150
- const wsolAta = getAssociatedTokenAddressSync(this.WSOL_ADDRESS, signer, true);
148
+ private async txsTransferSol(signer: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
149
+ const wsolAta = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, signer, true);
151
150
 
152
151
  const shouldUnwrap = await this.ataExists(wsolAta);
153
152
  const action = new SolanaAction(signer, this.root);
@@ -175,7 +174,7 @@ export class SolanaTokens extends SolanaModule {
175
174
  * @param feeRate fee rate to use for the transactions
176
175
  * @private
177
176
  */
178
- private async txsTransferTokens(signer: PublicKey, token: PublicKey, amount: BN, recipient: PublicKey, feeRate?: string) {
177
+ private async txsTransferTokens(signer: PublicKey, token: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string) {
179
178
  const srcAta = getAssociatedTokenAddressSync(token, signer, true);
180
179
  const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
181
180
 
@@ -238,8 +237,8 @@ export class SolanaTokens extends SolanaModule {
238
237
  /**
239
238
  * Returns the rent exempt deposit required to initiate the ATA
240
239
  */
241
- public getATARentExemptLamports(): Promise<BN> {
242
- return Promise.resolve(new BN(this.SPL_ATA_RENT_EXEMPT));
240
+ public getATARentExemptLamports(): Promise<bigint> {
241
+ return Promise.resolve(BigInt(SolanaTokens.SPL_ATA_RENT_EXEMPT));
243
242
  }
244
243
 
245
244
  /**
@@ -248,23 +247,23 @@ export class SolanaTokens extends SolanaModule {
248
247
  * @param publicKey
249
248
  * @param token
250
249
  */
251
- public async getTokenBalance(publicKey: PublicKey, token: PublicKey): Promise<{balance: BN, ataExists: boolean}> {
250
+ public async getTokenBalance(publicKey: PublicKey, token: PublicKey): Promise<{balance: bigint, ataExists: boolean}> {
252
251
  const ata: PublicKey = getAssociatedTokenAddressSync(token, publicKey, true);
253
252
  const [ataAccount, balance] = await Promise.all<[Promise<Account>, Promise<number>]>([
254
253
  this.getATAOrNull(ata),
255
- (token!=null && token.equals(this.WSOL_ADDRESS)) ? this.connection.getBalance(publicKey) : Promise.resolve(null)
254
+ (token!=null && token.equals(SolanaTokens.WSOL_ADDRESS)) ? this.connection.getBalance(publicKey) : Promise.resolve(null)
256
255
  ]);
257
256
 
258
257
  let ataExists: boolean = ataAccount!=null;
259
- let sum: BN = new BN(0);
258
+ let sum: bigint = 0n;
260
259
  if(ataExists) {
261
- sum = sum.add(new BN(ataAccount.amount.toString()));
260
+ sum += ataAccount.amount;
262
261
  }
263
262
 
264
263
  if(balance!=null) {
265
- let balanceLamports: BN = new BN(balance);
266
- if(!ataExists) balanceLamports = balanceLamports.sub(await this.getATARentExemptLamports());
267
- if(!balanceLamports.isNeg()) sum = sum.add(balanceLamports);
264
+ let balanceLamports: bigint = BigInt(balance);
265
+ if(!ataExists) balanceLamports = balanceLamports - await this.getATARentExemptLamports();
266
+ if(balanceLamports >= 0n) sum += balanceLamports;
268
267
  }
269
268
 
270
269
  this.logger.debug("getTokenBalance(): token balance fetched, token: "+token.toString()+
@@ -277,7 +276,7 @@ export class SolanaTokens extends SolanaModule {
277
276
  * Returns the native currency address, we use WSOL address as placeholder for SOL
278
277
  */
279
278
  public getNativeCurrencyAddress(): PublicKey {
280
- return this.WSOL_ADDRESS;
279
+ return SolanaTokens.WSOL_ADDRESS;
281
280
  }
282
281
 
283
282
  /**
@@ -299,8 +298,8 @@ export class SolanaTokens extends SolanaModule {
299
298
  * @param dstAddress destination address of the recipient
300
299
  * @param feeRate fee rate to use for the transaction
301
300
  */
302
- public txsTransfer(signer:PublicKey, token: PublicKey, amount: BN, dstAddress: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
303
- if(this.WSOL_ADDRESS.equals(token)) {
301
+ public txsTransfer(signer:PublicKey, token: PublicKey, amount: bigint, dstAddress: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
302
+ if(SolanaTokens.WSOL_ADDRESS.equals(token)) {
304
303
  return this.txsTransferSol(signer, amount, dstAddress, feeRate);
305
304
  }
306
305
  return this.txsTransferTokens(signer, token, amount, dstAddress, feeRate);
@@ -223,7 +223,7 @@ export class SolanaTransactions extends SolanaModule {
223
223
  * optionally waits for confirmation of a batch of solana transactions
224
224
  *
225
225
  * @param signer
226
- * @param txs transactions to send
226
+ * @param _txs
227
227
  * @param waitForConfirmation whether to wait for transaction confirmations (this also makes sure the transactions
228
228
  * are re-sent at regular intervals)
229
229
  * @param abortSignal abort signal to abort waiting for transaction confirmations
@@ -231,43 +231,48 @@ export class SolanaTransactions extends SolanaModule {
231
231
  * are executed in order)
232
232
  * @param onBeforePublish a callback called before every transaction is published
233
233
  */
234
- public async sendAndConfirm(signer: SolanaSigner, txs: SolanaTx[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]> {
235
- await this.prepareTransactions(signer, txs)
236
- const signedTxs = await signer.wallet.signAllTransactions(txs.map(e => e.tx));
237
- signedTxs.forEach((tx, index) => {
238
- const solTx = txs[index];
239
- tx.lastValidBlockHeight = solTx.tx.lastValidBlockHeight;
240
- solTx.tx = tx
241
- });
242
-
234
+ public async sendAndConfirm(signer: SolanaSigner, _txs: SolanaTx[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]> {
243
235
  const options = {
244
236
  skipPreflight: true
245
237
  };
246
238
 
247
- this.logger.debug("sendAndConfirm(): sending transactions, count: "+txs.length+
239
+ this.logger.debug("sendAndConfirm(): sending transactions, count: "+_txs.length+
248
240
  " waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
249
241
 
250
242
  const signatures: string[] = [];
251
- if(parallel) {
252
- const promises: Promise<void>[] = [];
253
- for(let solTx of txs) {
254
- const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
255
- if(waitForConfirmation) promises.push(this.confirmTransaction(solTx, abortSignal, "confirmed"));
256
- signatures.push(signature);
257
- }
258
- if(promises.length>0) await Promise.all(promises);
259
- } else {
260
- for(let i=0;i<txs.length;i++) {
261
- const solTx = txs[i];
262
- const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
263
- const confirmPromise = this.confirmTransaction(solTx, abortSignal, "confirmed");
264
- //Don't await the last promise when !waitForConfirmation
265
- if(i<txs.length-1 || waitForConfirmation) await confirmPromise;
266
- signatures.push(signature);
243
+ for(let e=0;e<_txs.length;e+=50) {
244
+ const txs = _txs.slice(e, e+50);
245
+
246
+ await this.prepareTransactions(signer, txs)
247
+ const signedTxs = await signer.wallet.signAllTransactions(txs.map(e => e.tx));
248
+ signedTxs.forEach((tx, index) => {
249
+ const solTx = txs[index];
250
+ tx.lastValidBlockHeight = solTx.tx.lastValidBlockHeight;
251
+ solTx.tx = tx
252
+ });
253
+ this.logger.debug("sendAndConfirm(): sending transaction batch ("+e+".."+(e+50)+"), count: "+txs.length);
254
+
255
+ if(parallel) {
256
+ const promises: Promise<void>[] = [];
257
+ for(let solTx of txs) {
258
+ const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
259
+ if(waitForConfirmation) promises.push(this.confirmTransaction(solTx, abortSignal, "confirmed"));
260
+ signatures.push(signature);
261
+ }
262
+ if(promises.length>0) await Promise.all(promises);
263
+ } else {
264
+ for(let i=0;i<txs.length;i++) {
265
+ const solTx = txs[i];
266
+ const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
267
+ const confirmPromise = this.confirmTransaction(solTx, abortSignal, "confirmed");
268
+ //Don't await the last promise when !waitForConfirmation
269
+ if(i<txs.length-1 || e+50<_txs.length || waitForConfirmation) await confirmPromise;
270
+ signatures.push(signature);
271
+ }
267
272
  }
268
273
  }
269
274
 
270
- this.logger.info("sendAndConfirm(): sent transactions, count: "+txs.length+
275
+ this.logger.info("sendAndConfirm(): sent transactions, count: "+_txs.length+
271
276
  " waitForConfirmation: "+waitForConfirmation+" parallel: "+parallel);
272
277
 
273
278
  return signatures;
@@ -1,4 +1,3 @@
1
- import {AnchorProvider} from "@coral-xyz/anchor";
2
1
  import {
3
2
  Connection,
4
3
  PublicKey,
@@ -12,15 +11,12 @@ import * as programIdl from "./program/programIdl.json";
12
11
  import {BitcoinRpc, BtcBlock, BtcRelay, StatePredictorUtils} from "@atomiqlabs/base";
13
12
  import {MethodsBuilder} from "@coral-xyz/anchor/dist/cjs/program/namespace/methods";
14
13
  import {SolanaProgramBase} from "../program/SolanaProgramBase";
15
- import * as BN from "bn.js";
16
14
  import {SolanaAction} from "../base/SolanaAction";
17
15
  import {Buffer} from "buffer";
18
16
  import {SolanaFees} from "../base/modules/SolanaFees";
19
17
  import {SolanaTx} from "../base/modules/SolanaTransactions";
20
18
  import {SolanaSigner} from "../wallet/SolanaSigner";
21
- import {sign} from "tweetnacl";
22
-
23
- const BASE_FEE_SOL_PER_BLOCKHEADER = new BN(5000);
19
+ import * as BN from "bn.js";
24
20
 
25
21
  const MAX_CLOSE_IX_PER_TX = 10;
26
22
 
@@ -540,15 +536,15 @@ export class SolanaBtcRelay<B extends BtcBlock> extends SolanaProgramBase<any> i
540
536
  * @param requiredBlockheight
541
537
  * @param feeRate
542
538
  */
543
- public async estimateSynchronizeFee(requiredBlockheight: number, feeRate?: string): Promise<BN> {
539
+ public async estimateSynchronizeFee(requiredBlockheight: number, feeRate?: string): Promise<bigint> {
544
540
  const tipData = await this.getTipData();
545
541
  const currBlockheight = tipData.blockheight;
546
542
 
547
543
  const blockheightDelta = requiredBlockheight-currBlockheight;
548
544
 
549
- if(blockheightDelta<=0) return new BN(0);
545
+ if(blockheightDelta<=0) return 0n;
550
546
 
551
- const synchronizationFee = new BN(blockheightDelta).mul(await this.getFeePerBlock(feeRate));
547
+ const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
552
548
  this.logger.debug("estimateSynchronizeFee(): required blockheight: "+requiredBlockheight+
553
549
  " blockheight delta: "+blockheightDelta+" fee: "+synchronizationFee.toString(10));
554
550
 
@@ -560,10 +556,10 @@ export class SolanaBtcRelay<B extends BtcBlock> extends SolanaProgramBase<any> i
560
556
  *
561
557
  * @param feeRate
562
558
  */
563
- public async getFeePerBlock(feeRate?: string): Promise<BN> {
559
+ public async getFeePerBlock(feeRate?: string): Promise<bigint> {
564
560
  // feeRate = feeRate || await this.getMainFeeRate(null);
565
561
  // return BASE_FEE_SOL_PER_BLOCKHEADER.add(this.Fees.getPriorityFee(200000, feeRate, false));
566
- return new BN(50000);
562
+ return 50000n;
567
563
  }
568
564
 
569
565
  /**
@@ -1,10 +1,10 @@
1
1
  import {ChainEvents, ClaimEvent, EventListener, InitializeEvent, RefundEvent, SwapEvent} from "@atomiqlabs/base";
2
2
  import {SolanaSwapData} from "../swaps/SolanaSwapData";
3
- import {AnchorProvider, IdlEvents} from "@coral-xyz/anchor";
3
+ import {IdlEvents} from "@coral-xyz/anchor";
4
4
  import {SolanaSwapProgram} from "../swaps/SolanaSwapProgram";
5
5
  import {
6
6
  getLogger,
7
- onceAsync, tryWithRetries
7
+ onceAsync, toEscrowHash, tryWithRetries
8
8
  } from "../../utils/Utils";
9
9
  import {Connection, ParsedTransactionWithMeta, PublicKey} from "@solana/web3.js";
10
10
  import * as BN from "bn.js";
@@ -132,11 +132,11 @@ export class SolanaChainEventsBrowser implements ChainEvents<SolanaSwapData> {
132
132
  protected parseInitializeEvent(data: IdlEvents<SwapProgram>["InitializeEvent"], eventObject: EventObject): InitializeEvent<SolanaSwapData> {
133
133
  const paymentHash: string = Buffer.from(data.hash).toString("hex");
134
134
  const txoHash: string = Buffer.from(data.txoHash).toString("hex");
135
- this.logger.debug("InitializeEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+" txoHash: "+txoHash);
135
+ const escrowHash = toEscrowHash(paymentHash, data.sequence);
136
+ this.logger.debug("InitializeEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+
137
+ " txoHash: "+txoHash+" escrowHash: "+escrowHash);
136
138
  return new InitializeEvent<SolanaSwapData>(
137
- paymentHash,
138
- data.sequence,
139
- txoHash,
139
+ escrowHash,
140
140
  SwapTypeEnum.toChainSwapType(data.kind),
141
141
  onceAsync<SolanaSwapData>(this.getSwapDataGetter(eventObject, txoHash))
142
142
  );
@@ -144,15 +144,19 @@ export class SolanaChainEventsBrowser implements ChainEvents<SolanaSwapData> {
144
144
 
145
145
  protected parseRefundEvent(data: IdlEvents<SwapProgram>["RefundEvent"]): RefundEvent<SolanaSwapData> {
146
146
  const paymentHash: string = Buffer.from(data.hash).toString("hex");
147
- this.logger.debug("RefundEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10));
148
- return new RefundEvent<SolanaSwapData>(paymentHash, data.sequence);
147
+ const escrowHash = toEscrowHash(paymentHash, data.sequence);
148
+ this.logger.debug("RefundEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+
149
+ " escrowHash: "+escrowHash);
150
+ return new RefundEvent<SolanaSwapData>(escrowHash);
149
151
  }
150
152
 
151
153
  protected parseClaimEvent(data: IdlEvents<SwapProgram>["ClaimEvent"]): ClaimEvent<SolanaSwapData> {
152
154
  const secret: string = Buffer.from(data.secret).toString("hex");
153
155
  const paymentHash: string = Buffer.from(data.hash).toString("hex");
154
- this.logger.debug("ClaimEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+" secret: "+secret);
155
- return new ClaimEvent<SolanaSwapData>(paymentHash, data.sequence, secret);
156
+ const escrowHash = toEscrowHash(paymentHash, data.sequence);
157
+ this.logger.debug("ClaimEvent paymentHash: "+paymentHash+" sequence: "+data.sequence.toString(10)+
158
+ " secret: "+secret+" escrowHash: "+escrowHash);
159
+ return new ClaimEvent<SolanaSwapData>(escrowHash, secret);
156
160
  }
157
161
 
158
162
  /**
@@ -1,5 +1,5 @@
1
1
  import {SolanaEvents} from "../../base/modules/SolanaEvents";
2
- import {BorshCoder, DecodeType, Event, EventParser, Idl, IdlEvents, IdlTypes, Instruction} from "@coral-xyz/anchor";
2
+ import {BorshCoder, DecodeType, Event, EventParser, Idl, IdlTypes, Instruction} from "@coral-xyz/anchor";
3
3
  import {IdlField, IdlInstruction} from "@coral-xyz/anchor/dist/cjs/idl";
4
4
  import {ConfirmedSignatureInfo, ParsedMessage, PartiallyDecodedInstruction, PublicKey} from "@solana/web3.js";
5
5
  import {SolanaProgramBase} from "../SolanaProgramBase";