@atomiqlabs/chain-solana 11.0.0 → 12.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.
@@ -7,4 +7,5 @@ import { SolanaSwapData } from "./swaps/SolanaSwapData";
7
7
  import { SolanaChainEventsBrowser } from "./events/SolanaChainEventsBrowser";
8
8
  import { SolanaBtcRelay } from "./btcrelay/SolanaBtcRelay";
9
9
  import { SolanaChainInterface } from "./chain/SolanaChainInterface";
10
- export type SolanaChainType = ChainType<"SOLANA", SolanaPreFetchData, SolanaPreFetchVerification, SolanaTx, SolanaSigner, SolanaSwapData, SolanaSwapProgram, SolanaChainInterface, SolanaChainEventsBrowser, SolanaBtcRelay<any>, never, never, never>;
10
+ import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider";
11
+ export type SolanaChainType = ChainType<"SOLANA", SolanaPreFetchData, SolanaPreFetchVerification, SolanaTx, SolanaSigner, Wallet, SolanaSwapData, SolanaSwapProgram, SolanaChainInterface, SolanaChainEventsBrowser, SolanaBtcRelay<any>, never, never, never>;
@@ -10,13 +10,14 @@ import { SolanaEvents } from "./modules/SolanaEvents";
10
10
  import { ChainInterface, TransactionConfirmationOptions } from "@atomiqlabs/base";
11
11
  import { SolanaSigner } from "../wallet/SolanaSigner";
12
12
  import { Buffer } from "buffer";
13
+ import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider";
13
14
  export type SolanaRetryPolicy = {
14
15
  maxRetries?: number;
15
16
  delay?: number;
16
17
  exponential?: boolean;
17
18
  transactionResendInterval?: number;
18
19
  };
19
- export declare class SolanaChainInterface implements ChainInterface<SolanaTx, SolanaSigner, "SOLANA"> {
20
+ export declare class SolanaChainInterface implements ChainInterface<SolanaTx, SolanaSigner, "SOLANA", Wallet> {
20
21
  readonly chainId = "SOLANA";
21
22
  readonly SLOT_TIME = 400;
22
23
  readonly TX_SLOT_VALIDITY = 151;
@@ -38,6 +39,7 @@ export declare class SolanaChainInterface implements ChainInterface<SolanaTx, So
38
39
  constructor(connection: Connection, retryPolicy?: SolanaRetryPolicy, solanaFeeEstimator?: SolanaFees);
39
40
  getBalance(signer: string, tokenAddress: string): Promise<bigint>;
40
41
  isValidAddress(address: string): boolean;
42
+ normalizeAddress(address: string): string;
41
43
  getNativeCurrencyAddress(): string;
42
44
  txsTransfer(signer: string, token: string, amount: bigint, dstAddress: string, feeRate?: string): Promise<SolanaTx[]>;
43
45
  transfer(signer: SolanaSigner, token: string, amount: bigint, dstAddress: string, txOptions?: TransactionConfirmationOptions): Promise<string>;
@@ -46,6 +48,10 @@ export declare class SolanaChainInterface implements ChainInterface<SolanaTx, So
46
48
  deserializeTx(txData: string): Promise<SolanaTx>;
47
49
  getTxIdStatus(txId: string): Promise<"not_found" | "pending" | "success" | "reverted">;
48
50
  getTxStatus(tx: string): Promise<"not_found" | "pending" | "success" | "reverted">;
51
+ getFinalizedBlock(): Promise<{
52
+ height: number;
53
+ blockHash: string;
54
+ }>;
49
55
  offBeforeTxReplace(callback: (oldTx: string, oldTxId: string, newTx: string, newTxId: string) => Promise<void>): boolean;
50
56
  onBeforeTxReplace(callback: (oldTx: string, oldTxId: string, newTx: string, newTxId: string) => Promise<void>): void;
51
57
  onBeforeTxSigned(callback: (tx: SolanaTx) => Promise<void>): void;
@@ -55,4 +61,5 @@ export declare class SolanaChainInterface implements ChainInterface<SolanaTx, So
55
61
  isValidToken(tokenIdentifier: string): boolean;
56
62
  randomAddress(): string;
57
63
  randomSigner(): SolanaSigner;
64
+ wrapSigner(signer: Wallet): Promise<SolanaSigner>;
58
65
  }
@@ -45,6 +45,9 @@ class SolanaChainInterface {
45
45
  isValidAddress(address) {
46
46
  return SolanaAddresses_1.SolanaAddresses.isValidAddress(address);
47
47
  }
48
+ normalizeAddress(address) {
49
+ return address;
50
+ }
48
51
  getNativeCurrencyAddress() {
49
52
  return this.Tokens.getNativeCurrencyAddress().toString();
50
53
  }
@@ -73,6 +76,13 @@ class SolanaChainInterface {
73
76
  getTxStatus(tx) {
74
77
  return this.Transactions.getTxStatus(tx);
75
78
  }
79
+ async getFinalizedBlock() {
80
+ const { block } = await this.Blocks.findLatestParsedBlock("finalized");
81
+ return {
82
+ height: block.blockHeight,
83
+ blockHash: block.blockhash
84
+ };
85
+ }
76
86
  ///////////////////////////////////
77
87
  //// Callbacks & handlers
78
88
  offBeforeTxReplace(callback) {
@@ -108,5 +118,8 @@ class SolanaChainInterface {
108
118
  const wallet = new SolanaKeypairWallet_1.SolanaKeypairWallet(keypair);
109
119
  return new SolanaSigner_1.SolanaSigner(wallet, keypair);
110
120
  }
121
+ wrapSigner(signer) {
122
+ return Promise.resolve(new SolanaSigner_1.SolanaSigner(signer));
123
+ }
111
124
  }
112
125
  exports.SolanaChainInterface = SolanaChainInterface;
@@ -1,7 +1,8 @@
1
1
  import { SolanaModule } from "../SolanaModule";
2
- import { ConfirmedSignatureInfo, PublicKey } from "@solana/web3.js";
2
+ import { ConfirmedSignatureInfo, ParsedTransactionWithMeta, PublicKey } from "@solana/web3.js";
3
3
  export declare class SolanaEvents extends SolanaModule {
4
4
  readonly LOG_FETCH_LIMIT = 500;
5
+ private usingHeliusTFA;
5
6
  /**
6
7
  * Gets the signatures for a given topicKey public key, if lastProcessedSignature is specified, it fetches only
7
8
  * the signatures before this signature
@@ -12,6 +13,43 @@ export declare class SolanaEvents extends SolanaModule {
12
13
  * @private
13
14
  */
14
15
  private getSignatures;
16
+ /**
17
+ * Implements Helius getTransactionsForAddress RPC API
18
+ *
19
+ * @param account
20
+ * @param options
21
+ * @param commitment
22
+ */
23
+ getTransactionsForAddress(account: PublicKey, options?: {
24
+ paginationToken?: string;
25
+ filters?: {
26
+ slot?: {
27
+ gte?: number;
28
+ lte?: number;
29
+ gt?: number;
30
+ lt?: number;
31
+ };
32
+ blockTime?: {
33
+ gte?: number;
34
+ lte?: number;
35
+ gt?: number;
36
+ lt?: number;
37
+ eq?: number;
38
+ };
39
+ signature?: {
40
+ gte?: number;
41
+ lte?: number;
42
+ gt?: number;
43
+ lt?: number;
44
+ eq?: number;
45
+ };
46
+ status?: "succeeded" | "failed" | "any";
47
+ };
48
+ }, commitment?: "finalized" | "confirmed" | "processed"): Promise<{
49
+ data: ParsedTransactionWithMeta[];
50
+ paginationToken?: string;
51
+ }>;
52
+ private _findInTxsTFA;
15
53
  /**
16
54
  * Runs a search backwards in time, processing transaction signatures for a specific topic public key
17
55
  *
@@ -20,6 +58,11 @@ export declare class SolanaEvents extends SolanaModule {
20
58
  * was found, or null if the search should continue
21
59
  * @param abortSignal
22
60
  * @param logFetchLimit
61
+ * @param startBlockheight
23
62
  */
24
- findInSignatures<T>(topicKey: PublicKey, processor: (signatures: ConfirmedSignatureInfo[]) => Promise<T>, abortSignal?: AbortSignal, logFetchLimit?: number): Promise<T>;
63
+ private _findInSignatures;
64
+ findInSignatures<T>(topicKey: PublicKey, processor: (data: {
65
+ signatures?: ConfirmedSignatureInfo[];
66
+ txs?: ParsedTransactionWithMeta[];
67
+ }) => Promise<T>, abortSignal?: AbortSignal, logFetchLimit?: number, startBlockheight?: number): Promise<T>;
25
68
  }
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SolanaEvents = void 0;
4
4
  const SolanaModule_1 = require("../SolanaModule");
5
+ const web3_js_1 = require("@solana/web3.js");
5
6
  class SolanaEvents extends SolanaModule_1.SolanaModule {
6
7
  constructor() {
7
8
  super(...arguments);
8
9
  this.LOG_FETCH_LIMIT = 500;
10
+ this.usingHeliusTFA = "auto";
9
11
  }
10
12
  /**
11
13
  * Gets the signatures for a given topicKey public key, if lastProcessedSignature is specified, it fetches only
@@ -29,6 +31,147 @@ class SolanaEvents extends SolanaModule_1.SolanaModule {
29
31
  }, "confirmed");
30
32
  }
31
33
  }
34
+ /**
35
+ * Implements Helius getTransactionsForAddress RPC API
36
+ *
37
+ * @param account
38
+ * @param options
39
+ * @param commitment
40
+ */
41
+ async getTransactionsForAddress(account, options, commitment) {
42
+ //Try to use getPriorityFeeEstimate api of Helius
43
+ const response = await this.connection._rpcRequest("getTransactionsForAddress", [
44
+ account.toString(),
45
+ {
46
+ ...options,
47
+ transactionDetails: "full",
48
+ sortOrder: "desc",
49
+ limit: 100,
50
+ commitment: commitment ?? "confirmed",
51
+ encoding: "jsonParsed",
52
+ maxSupportedTransactionVersion: 0
53
+ }
54
+ ]).catch(e => {
55
+ //Catching not supported errors
56
+ if (e.message != null && (e.message.includes("-32601") || e.message.includes("-32600"))) {
57
+ return {
58
+ error: {
59
+ code: -32601,
60
+ message: e.message
61
+ }
62
+ };
63
+ }
64
+ throw e;
65
+ });
66
+ if (response.error != null) {
67
+ //Catching not supported errors
68
+ if (response.error.code !== -32601 && response.error.code !== -32600)
69
+ throw new Error(response.error.message);
70
+ return null;
71
+ }
72
+ return {
73
+ data: response.result.data.map(val => {
74
+ return {
75
+ ...val,
76
+ meta: val.meta == null ? undefined : {
77
+ //ParsedTransactionMeta
78
+ ...val.meta,
79
+ innerInstructions: val.meta.innerInstructions == null ? undefined : val.meta.innerInstructions.map(innerIx => ({
80
+ //ParsedInnerInstruction
81
+ ...innerIx,
82
+ instructions: innerIx.instructions.map(ix => {
83
+ if (ix.program != null && ix.programId != null) {
84
+ return {
85
+ //ParsedInstruction
86
+ ...ix,
87
+ programId: new web3_js_1.PublicKey(ix.programId)
88
+ };
89
+ }
90
+ else {
91
+ return {
92
+ //PartiallyDecodedInstruction
93
+ data: ix.data,
94
+ programId: new web3_js_1.PublicKey(ix.programId),
95
+ accounts: ix.accounts.map(pubkey => new web3_js_1.PublicKey(pubkey))
96
+ };
97
+ }
98
+ })
99
+ })),
100
+ loadedAddresses: val.meta.loadedAddresses == null ? undefined : {
101
+ writable: val.meta.loadedAddresses.writable.map(pubkey => new web3_js_1.PublicKey(pubkey)),
102
+ readonly: val.meta.loadedAddresses.readonly.map(pubkey => new web3_js_1.PublicKey(pubkey)),
103
+ }
104
+ },
105
+ transaction: {
106
+ //ParsedTransaction
107
+ ...val.transaction,
108
+ message: {
109
+ //ParsedMessage
110
+ ...val.transaction.message,
111
+ accountKeys: val.transaction.message.accountKeys.map(accountKey => ({
112
+ //ParsedMessageAccount
113
+ ...accountKey,
114
+ pubkey: new web3_js_1.PublicKey(accountKey.pubkey)
115
+ })),
116
+ instructions: val.transaction.message.instructions.map(ix => {
117
+ if (ix.program != null && ix.programId != null) {
118
+ return {
119
+ //ParsedInstruction
120
+ ...ix,
121
+ programId: new web3_js_1.PublicKey(ix.programId)
122
+ };
123
+ }
124
+ else {
125
+ return {
126
+ //PartiallyDecodedInstruction
127
+ data: ix.data,
128
+ programId: new web3_js_1.PublicKey(ix.programId),
129
+ accounts: ix.accounts.map(pubkey => new web3_js_1.PublicKey(pubkey))
130
+ };
131
+ }
132
+ }),
133
+ addressTableLookups: val.transaction.message.addressTableLookups == null ? undefined : val.transaction.message.addressTableLookups.map(addressTableLookup => ({
134
+ //ParsedAddressTableLookup
135
+ ...addressTableLookup,
136
+ accountKey: new web3_js_1.PublicKey(addressTableLookup.accountKey)
137
+ }))
138
+ }
139
+ }
140
+ };
141
+ }),
142
+ paginationToken: response.result.paginationToken
143
+ };
144
+ }
145
+ async _findInTxsTFA(topicKey, processor, abortSignal, startBlockheight) {
146
+ let paginationToken;
147
+ let txs = null;
148
+ while (txs == null || txs.length > 0) {
149
+ let filters = startBlockheight != null ? {
150
+ slot: { gte: startBlockheight }
151
+ } : {};
152
+ const tfaResult = await this.getTransactionsForAddress(topicKey, {
153
+ paginationToken,
154
+ filters: {
155
+ ...filters,
156
+ status: "succeeded"
157
+ }
158
+ }, "confirmed");
159
+ if (tfaResult == null) {
160
+ //Not supported
161
+ return undefined;
162
+ }
163
+ txs = tfaResult.data;
164
+ paginationToken = tfaResult.paginationToken;
165
+ if (abortSignal != null)
166
+ abortSignal.throwIfAborted();
167
+ const result = await processor({ txs });
168
+ if (result != null)
169
+ return result;
170
+ if (paginationToken == null)
171
+ break;
172
+ }
173
+ return null;
174
+ }
32
175
  /**
33
176
  * Runs a search backwards in time, processing transaction signatures for a specific topic public key
34
177
  *
@@ -37,16 +180,24 @@ class SolanaEvents extends SolanaModule_1.SolanaModule {
37
180
  * was found, or null if the search should continue
38
181
  * @param abortSignal
39
182
  * @param logFetchLimit
183
+ * @param startBlockheight
40
184
  */
41
- async findInSignatures(topicKey, processor, abortSignal, logFetchLimit) {
185
+ async _findInSignatures(topicKey, processor, abortSignal, logFetchLimit, startBlockheight) {
42
186
  if (logFetchLimit == null || logFetchLimit > this.LOG_FETCH_LIMIT)
43
187
  logFetchLimit = this.LOG_FETCH_LIMIT;
44
188
  let signatures = null;
45
189
  while (signatures == null || signatures.length > 0) {
46
190
  signatures = await this.getSignatures(topicKey, logFetchLimit, signatures != null ? signatures[signatures.length - 1].signature : null);
191
+ if (startBlockheight != null) {
192
+ const endIndex = signatures.findIndex(val => val.slot < startBlockheight);
193
+ if (endIndex === 0)
194
+ return null;
195
+ if (endIndex !== -1)
196
+ signatures = signatures.slice(0, endIndex - 1);
197
+ }
47
198
  if (abortSignal != null)
48
199
  abortSignal.throwIfAborted();
49
- const result = await processor(signatures);
200
+ const result = await processor({ signatures });
50
201
  if (result != null)
51
202
  return result;
52
203
  if (signatures.length < logFetchLimit)
@@ -54,5 +205,19 @@ class SolanaEvents extends SolanaModule_1.SolanaModule {
54
205
  }
55
206
  return null;
56
207
  }
208
+ async findInSignatures(topicKey, processor, abortSignal, logFetchLimit, startBlockheight) {
209
+ if (this.usingHeliusTFA !== "no") {
210
+ //Attempt to use Helius's gTFA
211
+ const result = await this._findInTxsTFA(topicKey, processor, abortSignal, startBlockheight);
212
+ if (result !== undefined)
213
+ return result;
214
+ //Not supported
215
+ if (this.usingHeliusTFA === "yes")
216
+ throw new Error("Helius gTFA is not supported with current provider!");
217
+ //If set to auto, we can manually set to "no"
218
+ this.usingHeliusTFA = "no";
219
+ }
220
+ return await this._findInSignatures(topicKey, processor, abortSignal, logFetchLimit, startBlockheight);
221
+ }
57
222
  }
58
223
  exports.SolanaEvents = SolanaEvents;
@@ -6,6 +6,7 @@ const SolanaModule_1 = require("../SolanaModule");
6
6
  const bs58 = require("bs58");
7
7
  const Utils_1 = require("../../../utils/Utils");
8
8
  const buffer_1 = require("buffer");
9
+ const base_1 = require("@atomiqlabs/base");
9
10
  class SolanaTransactions extends SolanaModule_1.SolanaModule {
10
11
  /**
11
12
  * Sends raw solana transaction, first through the cbkSendTransaction callback (for e.g. sending the transaction
@@ -54,7 +55,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
54
55
  resolve(signature);
55
56
  }
56
57
  if (status === "reverted")
57
- reject(new Error("Transaction reverted!"));
58
+ reject(new base_1.TransactionRevertedError("Transaction reverted!"));
58
59
  clearInterval(watchdogInterval);
59
60
  }, this.retryPolicy?.transactionResendInterval || 3000);
60
61
  if (abortSignal != null)
@@ -95,7 +96,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
95
96
  if (status === "success")
96
97
  return signature;
97
98
  if (status === "reverted")
98
- throw new Error("Transaction reverted!");
99
+ throw new base_1.TransactionRevertedError("Transaction reverted!");
99
100
  if (err instanceof web3_js_1.TransactionExpiredBlockheightExceededError || err.toString().startsWith("TransactionExpiredBlockheightExceededError")) {
100
101
  throw new Error("Transaction expired before confirmation, please try again!");
101
102
  }
@@ -104,7 +105,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
104
105
  }
105
106
  }
106
107
  if (result.value.err != null)
107
- throw new Error("Transaction reverted!");
108
+ throw new base_1.TransactionRevertedError("Transaction reverted!");
108
109
  return signature;
109
110
  }
110
111
  /**
@@ -209,9 +210,10 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
209
210
  };
210
211
  this.logger.debug("sendAndConfirm(): sending transactions, count: " + _txs.length +
211
212
  " waitForConfirmation: " + waitForConfirmation + " parallel: " + parallel);
213
+ const BATCH_SIZE = 50;
212
214
  const signatures = [];
213
- for (let e = 0; e < _txs.length; e += 50) {
214
- const txs = _txs.slice(e, e + 50);
215
+ for (let e = 0; e < _txs.length; e += BATCH_SIZE) {
216
+ const txs = _txs.slice(e, e + BATCH_SIZE);
215
217
  await this.prepareTransactions(signer, txs);
216
218
  const signedTxs = await signer.wallet.signAllTransactions(txs.map(e => e.tx));
217
219
  signedTxs.forEach((tx, index) => {
@@ -220,27 +222,16 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
220
222
  solTx.tx = tx;
221
223
  });
222
224
  this.logger.debug("sendAndConfirm(): sending transaction batch (" + e + ".." + (e + 50) + "), count: " + txs.length);
223
- if (parallel) {
224
- const promises = [];
225
- for (let solTx of txs) {
226
- const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
227
- if (waitForConfirmation)
228
- promises.push(this.confirmTransaction(solTx, abortSignal, "confirmed"));
229
- signatures.push(signature);
230
- }
231
- if (promises.length > 0)
232
- await Promise.all(promises);
233
- }
234
- else {
235
- for (let i = 0; i < txs.length; i++) {
236
- const solTx = txs[i];
237
- const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
238
- const confirmPromise = this.confirmTransaction(solTx, abortSignal, "confirmed");
239
- //Don't await the last promise when !waitForConfirmation
240
- if (i < txs.length - 1 || e + 50 < _txs.length || waitForConfirmation)
241
- await confirmPromise;
242
- signatures.push(signature);
243
- }
225
+ //For solana we are forced to send txs one-by-one even with parallel, as we cannot determine their order upfront,
226
+ // however e.g. Jito could possibly handle sending a single package of up to 5 txns in order.
227
+ for (let i = 0; i < txs.length; i++) {
228
+ const solTx = txs[i];
229
+ const signature = await this.sendSignedTransaction(solTx, options, onBeforePublish);
230
+ const confirmPromise = this.confirmTransaction(solTx, abortSignal, "confirmed");
231
+ //Don't await the last promise when !waitForConfirmation
232
+ if (i < txs.length - 1 || e + 50 < _txs.length || waitForConfirmation)
233
+ await confirmPromise;
234
+ signatures.push(signature);
244
235
  }
245
236
  }
246
237
  this.logger.info("sendAndConfirm(): sent transactions, count: " + _txs.length +
@@ -3,7 +3,7 @@ import { SolanaSwapData } from "../swaps/SolanaSwapData";
3
3
  import { IdlEvents } from "@coral-xyz/anchor";
4
4
  import { SolanaSwapProgram } from "../swaps/SolanaSwapProgram";
5
5
  import { Connection } from "@solana/web3.js";
6
- import { InstructionWithAccounts, ProgramEvent, SingleInstructionWithAccounts } from "../program/modules/SolanaProgramEvents";
6
+ import { InstructionWithAccounts, ProgramEvent } from "../program/modules/SolanaProgramEvents";
7
7
  import { SwapProgram } from "../swaps/programTypes";
8
8
  export type EventObject = {
9
9
  events: ProgramEvent<SwapProgram>[];
@@ -11,7 +11,6 @@ export type EventObject = {
11
11
  blockTime: number;
12
12
  signature: string;
13
13
  };
14
- export type InitInstruction = SingleInstructionWithAccounts<SwapProgram["instructions"][2 | 3], SwapProgram>;
15
14
  /**
16
15
  * Solana on-chain event handler for front-end systems without access to fs, uses pure WS to subscribe, might lose
17
16
  * out on some events if the network is unreliable, front-end systems should take this into consideration and not
@@ -36,15 +35,6 @@ export declare class SolanaChainEventsBrowser implements ChainEvents<SolanaSwapD
36
35
  * @returns {Promise<InstructionWithAccounts<SwapProgram>[]>} array of parsed instructions
37
36
  */
38
37
  private getTransactionInstructions;
39
- /**
40
- * Converts initialize instruction data into {SolanaSwapData}
41
- *
42
- * @param initIx
43
- * @param txoHash
44
- * @private
45
- * @returns {SolanaSwapData} converted and parsed swap data
46
- */
47
- private instructionToSwapData;
48
38
  /**
49
39
  * Returns async getter for fetching on-demand initialize event swap data
50
40
  *
@@ -4,8 +4,6 @@ exports.SolanaChainEventsBrowser = void 0;
4
4
  const base_1 = require("@atomiqlabs/base");
5
5
  const SolanaSwapData_1 = require("../swaps/SolanaSwapData");
6
6
  const Utils_1 = require("../../utils/Utils");
7
- const web3_js_1 = require("@solana/web3.js");
8
- const BN = require("bn.js");
9
7
  const SwapTypeEnum_1 = require("../swaps/SwapTypeEnum");
10
8
  const buffer_1 = require("buffer");
11
9
  /**
@@ -43,26 +41,6 @@ class SolanaChainEventsBrowser {
43
41
  return null;
44
42
  return this.solanaSwapProgram.Events.decodeInstructions(transaction.transaction.message);
45
43
  }
46
- /**
47
- * Converts initialize instruction data into {SolanaSwapData}
48
- *
49
- * @param initIx
50
- * @param txoHash
51
- * @private
52
- * @returns {SolanaSwapData} converted and parsed swap data
53
- */
54
- instructionToSwapData(initIx, txoHash) {
55
- const paymentHash = buffer_1.Buffer.from(initIx.data.swapData.hash);
56
- let securityDeposit = new BN(0);
57
- let claimerBounty = new BN(0);
58
- let payIn = true;
59
- if (initIx.name === "offererInitialize") {
60
- payIn = false;
61
- securityDeposit = initIx.data.securityDeposit;
62
- claimerBounty = initIx.data.claimerBounty;
63
- }
64
- return new SolanaSwapData_1.SolanaSwapData(initIx.accounts.offerer, initIx.accounts.claimer, initIx.accounts.mint, initIx.data.swapData.amount, paymentHash.toString("hex"), initIx.data.swapData.sequence, initIx.data.swapData.expiry, initIx.data.swapData.nonce, initIx.data.swapData.confirmations, initIx.data.swapData.payOut, SwapTypeEnum_1.SwapTypeEnum.toNumber(initIx.data.swapData.kind), payIn, initIx.name === "offererInitializePayIn" ? initIx.accounts.offererAta : web3_js_1.PublicKey.default, initIx.data.swapData.payOut ? initIx.accounts.claimerAta : web3_js_1.PublicKey.default, securityDeposit, claimerBounty, txoHash);
65
- }
66
44
  /**
67
45
  * Returns async getter for fetching on-demand initialize event swap data
68
46
  *
@@ -80,7 +58,7 @@ class SolanaChainEventsBrowser {
80
58
  const initIx = eventObject.instructions.find(ix => ix != null && (ix.name === "offererInitializePayIn" || ix.name === "offererInitialize"));
81
59
  if (initIx == null)
82
60
  return null;
83
- return this.instructionToSwapData(initIx, txoHash);
61
+ return SolanaSwapData_1.SolanaSwapData.fromInstruction(initIx, txoHash);
84
62
  };
85
63
  }
86
64
  parseInitializeEvent(data, eventObject) {
@@ -1,7 +1,7 @@
1
1
  import { SolanaEvents } from "../../chain/modules/SolanaEvents";
2
2
  import { DecodeType, Event, Idl, IdlTypes } from "@coral-xyz/anchor";
3
3
  import { IdlField, IdlInstruction } from "@coral-xyz/anchor/dist/cjs/idl";
4
- import { ConfirmedSignatureInfo, ParsedMessage, PublicKey } from "@solana/web3.js";
4
+ import { ParsedMessage, ParsedTransactionWithMeta, PublicKey } from "@solana/web3.js";
5
5
  import { SolanaProgramBase } from "../SolanaProgramBase";
6
6
  import { SolanaChainInterface } from "../../chain/SolanaChainInterface";
7
7
  type DecodedFieldOrNull<D, Defined> = D extends IdlField ? DecodeType<D["type"], Defined> : unknown;
@@ -25,13 +25,6 @@ export declare class SolanaProgramEvents<IDL extends Idl> extends SolanaEvents {
25
25
  private readonly program;
26
26
  private readonly nameMappedInstructions;
27
27
  constructor(chain: SolanaChainInterface, program: SolanaProgramBase<IDL>);
28
- /**
29
- * Gets events from specific transaction as specified by signature, events are ordered from newest to oldest
30
- *
31
- * @param signature
32
- * @private
33
- */
34
- private getEvents;
35
28
  /**
36
29
  * Runs a search backwards in time, processing the events for a specific topic public key
37
30
  *
@@ -40,8 +33,9 @@ export declare class SolanaProgramEvents<IDL extends Idl> extends SolanaEvents {
40
33
  * if the search should continue
41
34
  * @param abortSignal
42
35
  * @param logBatchSize how many signatures should be fetched in one getSignaturesForAddress call
36
+ * @param startBlockheight
43
37
  */
44
- findInEvents<T>(topicKey: PublicKey, processor: (event: ProgramEvent<IDL>, info: ConfirmedSignatureInfo) => Promise<T>, abortSignal?: AbortSignal, logBatchSize?: number): Promise<T>;
38
+ findInEvents<T>(topicKey: PublicKey, processor: (event: ProgramEvent<IDL>, tx: ParsedTransactionWithMeta) => Promise<T>, abortSignal?: AbortSignal, logBatchSize?: number, startBlockheight?: number): Promise<T>;
45
39
  /**
46
40
  * Decodes the instructions for this program from the transaction, leaves null in the returned instructions array
47
41
  * for every instruction that doesn't correspond to this program (as those are impossible to parse)
@@ -14,23 +14,6 @@ class SolanaProgramEvents extends SolanaEvents_1.SolanaEvents {
14
14
  this.nameMappedInstructions[ix.name] = ix;
15
15
  }
16
16
  }
17
- /**
18
- * Gets events from specific transaction as specified by signature, events are ordered from newest to oldest
19
- *
20
- * @param signature
21
- * @private
22
- */
23
- async getEvents(signature) {
24
- const tx = await this.connection.getTransaction(signature, {
25
- commitment: "confirmed",
26
- maxSupportedTransactionVersion: 0
27
- });
28
- if (tx.meta.err)
29
- return [];
30
- const events = this.parseLogs(tx.meta.logMessages);
31
- events.reverse();
32
- return events;
33
- }
34
17
  /**
35
18
  * Runs a search backwards in time, processing the events for a specific topic public key
36
19
  *
@@ -39,19 +22,47 @@ class SolanaProgramEvents extends SolanaEvents_1.SolanaEvents {
39
22
  * if the search should continue
40
23
  * @param abortSignal
41
24
  * @param logBatchSize how many signatures should be fetched in one getSignaturesForAddress call
25
+ * @param startBlockheight
42
26
  */
43
- findInEvents(topicKey, processor, abortSignal, logBatchSize) {
44
- return this.findInSignatures(topicKey, async (signatures) => {
45
- for (let data of signatures) {
46
- for (let event of await this.getEvents(data.signature)) {
47
- if (abortSignal != null)
48
- abortSignal.throwIfAborted();
49
- const result = await processor(event, data);
50
- if (result != null)
51
- return result;
27
+ findInEvents(topicKey, processor, abortSignal, logBatchSize, startBlockheight) {
28
+ return this.findInSignatures(topicKey, async (data) => {
29
+ if (data.signatures) {
30
+ for (let info of data.signatures) {
31
+ if (info.err == null)
32
+ continue;
33
+ const tx = await this.connection.getParsedTransaction(info.signature, {
34
+ commitment: "confirmed",
35
+ maxSupportedTransactionVersion: 0
36
+ });
37
+ if (tx.meta.err)
38
+ continue;
39
+ const events = this.parseLogs(tx.meta.logMessages);
40
+ events.reverse();
41
+ for (let event of events) {
42
+ if (abortSignal != null)
43
+ abortSignal.throwIfAborted();
44
+ const result = await processor(event, tx);
45
+ if (result != null)
46
+ return result;
47
+ }
48
+ }
49
+ }
50
+ else {
51
+ for (let tx of data.txs) {
52
+ if (tx.meta.err)
53
+ continue;
54
+ const events = this.parseLogs(tx.meta.logMessages);
55
+ events.reverse();
56
+ for (let event of events) {
57
+ if (abortSignal != null)
58
+ abortSignal.throwIfAborted();
59
+ const result = await processor(event, tx);
60
+ if (result != null)
61
+ return result;
62
+ }
52
63
  }
53
64
  }
54
- }, abortSignal, logBatchSize);
65
+ }, abortSignal, logBatchSize, startBlockheight);
55
66
  }
56
67
  /**
57
68
  * Decodes the instructions for this program from the transaction, leaves null in the returned instructions array