@atomiqlabs/chain-solana 9.0.0 → 10.0.0-dev.3

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.
@@ -1,4 +1,10 @@
1
1
  export declare const SolanaChains: {
2
+ readonly 2: {
3
+ readonly addresses: {
4
+ readonly swapContract: "11111111111111111111111111111111";
5
+ readonly btcRelayContract: "11111111111111111111111111111111";
6
+ };
7
+ };
2
8
  readonly 1: {
3
9
  readonly addresses: {
4
10
  readonly swapContract: "4hfUykhqmD7ZRvNh1HuzVKEY7ToENixtdUKZspNDCrEM";
@@ -3,6 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SolanaChains = void 0;
4
4
  const base_1 = require("@atomiqlabs/base");
5
5
  exports.SolanaChains = {
6
+ //TODO: Not deployed yet
7
+ [base_1.BitcoinNetwork.TESTNET4]: {
8
+ addresses: {
9
+ swapContract: "11111111111111111111111111111111",
10
+ btcRelayContract: "11111111111111111111111111111111"
11
+ }
12
+ },
6
13
  [base_1.BitcoinNetwork.TESTNET]: {
7
14
  addresses: {
8
15
  swapContract: "4hfUykhqmD7ZRvNh1HuzVKEY7ToENixtdUKZspNDCrEM",
@@ -107,7 +107,6 @@ class SolanaFees {
107
107
  });
108
108
  if (request.ok) {
109
109
  const parsedResponse = await request.json();
110
- // console.log(parsedResponse);
111
110
  return parsedResponse.result;
112
111
  }
113
112
  throw new Error(await request.text());
@@ -98,13 +98,11 @@ class SolanaChainEvents extends SolanaChainEventsBrowser_1.SolanaChainEventsBrow
98
98
  const eventObject = this.getEventObjectFromTransaction(transaction);
99
99
  if (eventObject == null)
100
100
  return true;
101
- console.log("Instructions: ", eventObject.instructions);
102
- console.log("Events: ", eventObject.events);
103
101
  await this.processEvent(eventObject);
104
102
  return true;
105
103
  }
106
104
  catch (e) {
107
- console.error(e);
105
+ this.logger.error("fetchTxAndProcessEvent(): Error fetching transaction and processing event, signature: " + signature, e);
108
106
  return false;
109
107
  }
110
108
  }
@@ -121,14 +119,14 @@ class SolanaChainEvents extends SolanaChainEventsBrowser_1.SolanaChainEventsBrow
121
119
  return;
122
120
  if (this.isSignatureProcessed(signature))
123
121
  return;
124
- console.log("[Solana Events WebSocket] Process signature: ", signature);
122
+ this.logger.debug("getWsEventHandler(" + name + "): Process signature: ", signature);
125
123
  this.signaturesProcessing[signature] = this.processEvent({
126
124
  events: [{ name, data: data }],
127
125
  instructions: null,
128
126
  blockTime: Math.floor(Date.now() / 1000),
129
127
  signature
130
128
  }).then(() => true).catch(e => {
131
- console.error(e);
129
+ this.logger.error("getWsEventHandler(" + name + "): Error processing signature: " + signature, e);
132
130
  return false;
133
131
  });
134
132
  };
@@ -150,7 +148,7 @@ class SolanaChainEvents extends SolanaChainEventsBrowser_1.SolanaChainEventsBrow
150
148
  }, "confirmed");
151
149
  //Check if newest returned signature (index 0) is older than the latest signature's slot, this is a sanity check
152
150
  if (fetched.length > 0 && fetched[0].slot < lastProcessedSignature.slot) {
153
- console.log("[Solana Events POLL] Sanity check triggered, returned signature slot height is older than latest!");
151
+ this.logger.debug("getNewSignatures(): Sanity check triggered, returned signature slot height is older than latest!");
154
152
  return;
155
153
  }
156
154
  }
@@ -198,7 +196,7 @@ class SolanaChainEvents extends SolanaChainEventsBrowser_1.SolanaChainEventsBrow
198
196
  continue;
199
197
  }
200
198
  }
201
- console.log("[Solana Events POLL] Process signature: ", txSignature);
199
+ this.logger.debug("processSignatures(): Process signature: ", txSignature);
202
200
  const processPromise = this.fetchTxAndProcessEvent(txSignature.signature);
203
201
  this.signaturesProcessing[txSignature.signature] = processPromise;
204
202
  const result = await processPromise;
@@ -210,7 +208,7 @@ class SolanaChainEvents extends SolanaChainEventsBrowser_1.SolanaChainEventsBrow
210
208
  }
211
209
  }
212
210
  catch (e) {
213
- console.error(e);
211
+ this.logger.error("processSignatures(): Failed processing signatures: ", e);
214
212
  }
215
213
  return lastSuccessfulSignature;
216
214
  }
@@ -232,8 +230,7 @@ class SolanaChainEvents extends SolanaChainEventsBrowser_1.SolanaChainEventsBrow
232
230
  let func;
233
231
  func = async () => {
234
232
  await this.checkEvents().catch(e => {
235
- console.error("Failed to fetch Sol log");
236
- console.error(e);
233
+ this.logger.error("setupHttpPolling(): Failed to fetch Solana log: ", e);
237
234
  });
238
235
  if (this.stopped)
239
236
  return;
@@ -153,7 +153,7 @@ class SolanaChainEventsBrowser {
153
153
  blockTime: Math.floor(Date.now() / 1000),
154
154
  signature
155
155
  }).then(() => true).catch(e => {
156
- console.error(e);
156
+ this.logger.error("wsEventHandler: Error when processing signature: " + signature, e);
157
157
  return false;
158
158
  });
159
159
  };
@@ -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 { ParsedMessage, PublicKey } from "@solana/web3.js";
4
+ import { ConfirmedSignatureInfo, ParsedMessage, 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;
@@ -41,7 +41,7 @@ export declare class SolanaProgramEvents<IDL extends Idl> extends SolanaEvents {
41
41
  * @param abortSignal
42
42
  * @param logBatchSize how many signatures should be fetched in one getSignaturesForAddress call
43
43
  */
44
- findInEvents<T>(topicKey: PublicKey, processor: (event: ProgramEvent<IDL>) => Promise<T>, abortSignal?: AbortSignal, logBatchSize?: number): Promise<T>;
44
+ findInEvents<T>(topicKey: PublicKey, processor: (event: ProgramEvent<IDL>, info: ConfirmedSignatureInfo) => Promise<T>, abortSignal?: AbortSignal, logBatchSize?: number): Promise<T>;
45
45
  /**
46
46
  * Decodes the instructions for this program from the transaction, leaves null in the returned instructions array
47
47
  * for every instruction that doesn't correspond to this program (as those are impossible to parse)
@@ -46,7 +46,7 @@ class SolanaProgramEvents extends SolanaEvents_1.SolanaEvents {
46
46
  for (let event of await this.getEvents(data.signature)) {
47
47
  if (abortSignal != null)
48
48
  abortSignal.throwIfAborted();
49
- const result = await processor(event);
49
+ const result = await processor(event, data);
50
50
  if (result != null)
51
51
  return result;
52
52
  }
@@ -2,7 +2,7 @@
2
2
  import { SolanaSwapData } from "./SolanaSwapData";
3
3
  import { PublicKey } from "@solana/web3.js";
4
4
  import { SolanaBtcRelay } from "../btcrelay/SolanaBtcRelay";
5
- import { IStorageManager, SwapContract, ChainSwapType, IntermediaryReputationType, SwapCommitStatus, TransactionConfirmationOptions, SignatureData, RelaySynchronizer } from "@atomiqlabs/base";
5
+ import { IStorageManager, SwapContract, ChainSwapType, IntermediaryReputationType, TransactionConfirmationOptions, SignatureData, RelaySynchronizer, SwapCommitState, SwapCommitStateType } from "@atomiqlabs/base";
6
6
  import { SolanaBtcStoredHeader } from "../btcrelay/headers/SolanaBtcStoredHeader";
7
7
  import { SwapProgram } from "./programTypes";
8
8
  import { SolanaChainInterface } from "../chain/SolanaChainInterface";
@@ -47,7 +47,7 @@ export declare class SolanaSwapProgram extends SolanaProgramBase<SwapProgram> im
47
47
  preFetchForInitSignatureVerification(data: SolanaPreFetchData): Promise<SolanaPreFetchVerification>;
48
48
  preFetchBlockDataForSignatures(): Promise<SolanaPreFetchData>;
49
49
  getInitSignature(signer: SolanaSigner, swapData: SolanaSwapData, authorizationTimeout: number, preFetchedBlockData?: SolanaPreFetchData, feeRate?: string): Promise<SignatureData>;
50
- isValidInitAuthorization(swapData: SolanaSwapData, { timeout, prefix, signature }: {
50
+ isValidInitAuthorization(signer: string, swapData: SolanaSwapData, { timeout, prefix, signature }: {
51
51
  timeout: any;
52
52
  prefix: any;
53
53
  signature: any;
@@ -117,13 +117,13 @@ export declare class SolanaSwapProgram extends SolanaProgramBase<SwapProgram> im
117
117
  * @param signer
118
118
  * @param data
119
119
  */
120
- getCommitStatus(signer: string, data: SolanaSwapData): Promise<SwapCommitStatus>;
120
+ getCommitStatus(signer: string, data: SolanaSwapData): Promise<SwapCommitState>;
121
121
  /**
122
122
  * Checks the status of the specific payment hash
123
123
  *
124
124
  * @param claimHash
125
125
  */
126
- getClaimHashStatus(claimHash: string): Promise<SwapCommitStatus>;
126
+ getClaimHashStatus(claimHash: string): Promise<SwapCommitStateType>;
127
127
  /**
128
128
  * Returns the data committed for a specific payment hash, or null if no data is currently commited for
129
129
  * the specific swap
@@ -155,7 +155,7 @@ export declare class SolanaSwapProgram extends SolanaProgramBase<SwapProgram> im
155
155
  prefix: any;
156
156
  signature: any;
157
157
  }, check?: boolean, initAta?: boolean, feeRate?: string): Promise<SolanaTx[]>;
158
- txsInit(swapData: SolanaSwapData, { timeout, prefix, signature }: {
158
+ txsInit(sender: string, swapData: SolanaSwapData, { timeout, prefix, signature }: {
159
159
  timeout: any;
160
160
  prefix: any;
161
161
  signature: any;
@@ -185,18 +185,18 @@ export declare class SolanaSwapProgram extends SolanaProgramBase<SwapProgram> im
185
185
  /**
186
186
  * Get the estimated solana fee of the commit transaction
187
187
  */
188
- getCommitFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
188
+ getCommitFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
189
189
  /**
190
190
  * Get the estimated solana fee of the commit transaction, without any deposits
191
191
  */
192
- getRawCommitFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
192
+ getRawCommitFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
193
193
  /**
194
194
  * Get the estimated solana transaction fee of the refund transaction
195
195
  */
196
- getRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
196
+ getRefundFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
197
197
  /**
198
198
  * Get the estimated solana transaction fee of the refund transaction
199
199
  */
200
- getRawRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
200
+ getRawRefundFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint>;
201
201
  getExtraData(outputScript: Buffer, amount: bigint, confirmations: number, nonce?: bigint): Buffer;
202
202
  }
@@ -67,8 +67,8 @@ class SolanaSwapProgram extends SolanaProgramBase_1.SolanaProgramBase {
67
67
  getInitSignature(signer, swapData, authorizationTimeout, preFetchedBlockData, feeRate) {
68
68
  return this.Init.signSwapInitialization(signer, swapData, authorizationTimeout, preFetchedBlockData, feeRate);
69
69
  }
70
- isValidInitAuthorization(swapData, { timeout, prefix, signature }, feeRate, preFetchedData) {
71
- return this.Init.isSignatureValid(swapData, timeout, prefix, signature, feeRate, preFetchedData);
70
+ isValidInitAuthorization(signer, swapData, { timeout, prefix, signature }, feeRate, preFetchedData) {
71
+ return this.Init.isSignatureValid(signer, swapData, timeout, prefix, signature, feeRate, preFetchedData);
72
72
  }
73
73
  getInitAuthorizationExpiry(swapData, { timeout, prefix, signature }, preFetchedData) {
74
74
  return this.Init.getSignatureExpiry(timeout, signature, preFetchedData);
@@ -186,34 +186,49 @@ class SolanaSwapProgram extends SolanaProgramBase_1.SolanaProgramBase {
186
186
  if (escrowState != null) {
187
187
  if (data.correctPDA(escrowState)) {
188
188
  if (data.isOfferer(signer) && isExpired)
189
- return base_1.SwapCommitStatus.REFUNDABLE;
190
- return base_1.SwapCommitStatus.COMMITED;
189
+ return { type: base_1.SwapCommitStateType.REFUNDABLE };
190
+ return { type: base_1.SwapCommitStateType.COMMITED };
191
191
  }
192
192
  if (data.isOfferer(signer) && isExpired)
193
- return base_1.SwapCommitStatus.EXPIRED;
194
- return base_1.SwapCommitStatus.NOT_COMMITED;
193
+ return { type: base_1.SwapCommitStateType.EXPIRED };
194
+ return { type: base_1.SwapCommitStateType.NOT_COMMITED };
195
195
  }
196
196
  //Check if paid or what
197
- const status = await this.Events.findInEvents(escrowStateKey, async (event) => {
197
+ const status = await this.Events.findInEvents(escrowStateKey, async (event, info) => {
198
198
  if (event.name === "ClaimEvent") {
199
199
  if (!event.data.sequence.eq(data.sequence))
200
200
  return null;
201
- return base_1.SwapCommitStatus.PAID;
201
+ return {
202
+ type: base_1.SwapCommitStateType.PAID,
203
+ getClaimTxId: () => Promise.resolve(info.signature),
204
+ getTxBlock: async () => {
205
+ return {
206
+ blockHeight: (await this.Chain.Blocks.getParsedBlock(info.slot)).blockHeight,
207
+ blockTime: info.blockTime
208
+ };
209
+ }
210
+ };
202
211
  }
203
212
  if (event.name === "RefundEvent") {
204
213
  if (!event.data.sequence.eq(data.sequence))
205
214
  return null;
206
- if (isExpired)
207
- return base_1.SwapCommitStatus.EXPIRED;
208
- return base_1.SwapCommitStatus.NOT_COMMITED;
215
+ return {
216
+ type: isExpired ? base_1.SwapCommitStateType.EXPIRED : base_1.SwapCommitStateType.NOT_COMMITED,
217
+ getRefundTxId: () => Promise.resolve(info.signature),
218
+ getTxBlock: async () => {
219
+ return {
220
+ blockHeight: (await this.Chain.Blocks.getParsedBlock(info.slot)).blockHeight,
221
+ blockTime: info.blockTime
222
+ };
223
+ }
224
+ };
209
225
  }
210
226
  });
211
227
  if (status != null)
212
228
  return status;
213
- if (isExpired) {
214
- return base_1.SwapCommitStatus.EXPIRED;
215
- }
216
- return base_1.SwapCommitStatus.NOT_COMMITED;
229
+ if (isExpired)
230
+ return { type: base_1.SwapCommitStateType.EXPIRED };
231
+ return { type: base_1.SwapCommitStateType.NOT_COMMITED };
217
232
  }
218
233
  /**
219
234
  * Checks the status of the specific payment hash
@@ -227,9 +242,9 @@ class SolanaSwapProgram extends SolanaProgramBase_1.SolanaProgramBase {
227
242
  //Start fetching events before checking escrow PDA, this call is used when quoting, so saving 100ms here helps a lot!
228
243
  const eventsPromise = this.Events.findInEvents(escrowStateKey, async (event) => {
229
244
  if (event.name === "ClaimEvent")
230
- return base_1.SwapCommitStatus.PAID;
245
+ return base_1.SwapCommitStateType.PAID;
231
246
  if (event.name === "RefundEvent")
232
- return base_1.SwapCommitStatus.NOT_COMMITED;
247
+ return base_1.SwapCommitStateType.NOT_COMMITED;
233
248
  }, abortController.signal).catch(e => {
234
249
  abortController.abort(e);
235
250
  return null;
@@ -238,14 +253,14 @@ class SolanaSwapProgram extends SolanaProgramBase_1.SolanaProgramBase {
238
253
  abortController.signal.throwIfAborted();
239
254
  if (escrowState != null) {
240
255
  abortController.abort();
241
- return base_1.SwapCommitStatus.COMMITED;
256
+ return base_1.SwapCommitStateType.COMMITED;
242
257
  }
243
258
  //Check if paid or what
244
259
  const eventsStatus = await eventsPromise;
245
260
  abortController.signal.throwIfAborted();
246
261
  if (eventsStatus != null)
247
262
  return eventsStatus;
248
- return base_1.SwapCommitStatus.NOT_COMMITED;
263
+ return base_1.SwapCommitStateType.NOT_COMMITED;
249
264
  }
250
265
  /**
251
266
  * Returns the data committed for a specific payment hash, or null if no data is currently commited for
@@ -313,11 +328,15 @@ class SolanaSwapProgram extends SolanaProgramBase_1.SolanaProgramBase {
313
328
  throw new Error("Only offerer can refund on Solana");
314
329
  return this.Refund.txsRefundWithAuthorization(swapData, timeout, prefix, signature, check, initAta, feeRate);
315
330
  }
316
- txsInit(swapData, { timeout, prefix, signature }, skipChecks, feeRate) {
331
+ txsInit(sender, swapData, { timeout, prefix, signature }, skipChecks, feeRate) {
317
332
  if (swapData.isPayIn()) {
333
+ if (!swapData.isOfferer(sender))
334
+ throw new Error("Only offerer can create payIn=true swap");
318
335
  return this.Init.txsInitPayIn(swapData, timeout, prefix, signature, skipChecks, feeRate);
319
336
  }
320
337
  else {
338
+ if (!swapData.isClaimer(sender))
339
+ throw new Error("Only claimer can create payIn=false swap");
321
340
  return this.Init.txsInit(swapData, timeout, prefix, signature, skipChecks, feeRate);
322
341
  }
323
342
  }
@@ -367,14 +386,14 @@ class SolanaSwapProgram extends SolanaProgramBase_1.SolanaProgramBase {
367
386
  if (!signer.getPublicKey().equals(swapData.claimer))
368
387
  throw new Error("Invalid signer provided!");
369
388
  }
370
- const result = await this.txsInit(swapData, signature, skipChecks, txOptions?.feeRate);
389
+ const result = await this.txsInit(signer.getAddress(), swapData, signature, skipChecks, txOptions?.feeRate);
371
390
  const [txSignature] = await this.Chain.sendAndConfirm(signer, result, txOptions?.waitForConfirmation, txOptions?.abortSignal);
372
391
  return txSignature;
373
392
  }
374
393
  async initAndClaimWithSecret(signer, swapData, signature, secret, skipChecks, txOptions) {
375
394
  if (!signer.getPublicKey().equals(swapData.claimer))
376
395
  throw new Error("Invalid signer provided!");
377
- const txsCommit = await this.txsInit(swapData, signature, skipChecks, txOptions?.feeRate);
396
+ const txsCommit = await this.txsInit(signer.getAddress(), swapData, signature, skipChecks, txOptions?.feeRate);
378
397
  const txsClaim = await this.Claim.txsClaimWithSecret(signer.getPublicKey(), swapData, secret, true, false, txOptions?.feeRate, true);
379
398
  return await this.Chain.sendAndConfirm(signer, txsCommit.concat(txsClaim), txOptions?.waitForConfirmation, txOptions?.abortSignal);
380
399
  }
@@ -413,25 +432,25 @@ class SolanaSwapProgram extends SolanaProgramBase_1.SolanaProgramBase {
413
432
  /**
414
433
  * Get the estimated solana fee of the commit transaction
415
434
  */
416
- getCommitFee(swapData, feeRate) {
435
+ getCommitFee(signer, swapData, feeRate) {
417
436
  return this.Init.getInitFee(swapData, feeRate);
418
437
  }
419
438
  /**
420
439
  * Get the estimated solana fee of the commit transaction, without any deposits
421
440
  */
422
- getRawCommitFee(swapData, feeRate) {
441
+ getRawCommitFee(signer, swapData, feeRate) {
423
442
  return this.Init.getRawInitFee(swapData, feeRate);
424
443
  }
425
444
  /**
426
445
  * Get the estimated solana transaction fee of the refund transaction
427
446
  */
428
- getRefundFee(swapData, feeRate) {
447
+ getRefundFee(signer, swapData, feeRate) {
429
448
  return this.Refund.getRefundFee(swapData, feeRate);
430
449
  }
431
450
  /**
432
451
  * Get the estimated solana transaction fee of the refund transaction
433
452
  */
434
- getRawRefundFee(swapData, feeRate) {
453
+ getRawRefundFee(signer, swapData, feeRate) {
435
454
  return this.Refund.getRawRefundFee(swapData, feeRate);
436
455
  }
437
456
  getExtraData(outputScript, amount, confirmations, nonce) {
@@ -135,6 +135,7 @@ export declare class SwapInit extends SolanaSwapModule {
135
135
  /**
136
136
  * Checks whether the provided signature data is valid, using preFetchedData if provided and still valid
137
137
  *
138
+ * @param sender
138
139
  * @param swapData
139
140
  * @param timeout
140
141
  * @param prefix
@@ -143,7 +144,7 @@ export declare class SwapInit extends SolanaSwapModule {
143
144
  * @param preFetchedData
144
145
  * @public
145
146
  */
146
- isSignatureValid(swapData: SolanaSwapData, timeout: string, prefix: string, signature: string, feeRate?: string, preFetchedData?: SolanaPreFetchVerification): Promise<Buffer>;
147
+ isSignatureValid(sender: string, swapData: SolanaSwapData, timeout: string, prefix: string, signature: string, feeRate?: string, preFetchedData?: SolanaPreFetchVerification): Promise<Buffer>;
147
148
  /**
148
149
  * Gets expiry of the provided signature data, this is a minimum of slot expiry & swap signature expiry
149
150
  *
@@ -257,6 +257,7 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
257
257
  /**
258
258
  * Checks whether the provided signature data is valid, using preFetchedData if provided and still valid
259
259
  *
260
+ * @param sender
260
261
  * @param swapData
261
262
  * @param timeout
262
263
  * @param prefix
@@ -265,8 +266,15 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
265
266
  * @param preFetchedData
266
267
  * @public
267
268
  */
268
- async isSignatureValid(swapData, timeout, prefix, signature, feeRate, preFetchedData) {
269
- const sender = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
269
+ async isSignatureValid(sender, swapData, timeout, prefix, signature, feeRate, preFetchedData) {
270
+ if (swapData.isPayIn()) {
271
+ if (!swapData.isOfferer(sender))
272
+ throw new base_1.SignatureVerificationError("Sender needs to be offerer in payIn=true swaps");
273
+ }
274
+ else {
275
+ if (!swapData.isClaimer(sender))
276
+ throw new base_1.SignatureVerificationError("Sender needs to be claimer in payIn=false swaps");
277
+ }
270
278
  const signer = swapData.isPayIn() ? swapData.claimer : swapData.offerer;
271
279
  if (!swapData.isPayIn() && await this.program.isExpired(sender.toString(), swapData)) {
272
280
  throw new base_1.SignatureVerificationError("Swap will expire too soon!");
@@ -288,7 +296,7 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
288
296
  if (slotsLeft < 0)
289
297
  throw new base_1.SignatureVerificationError("Authorization expired!");
290
298
  const txToSign = await this.getTxToSign(swapData, timeout, feeRate);
291
- txToSign.feePayer = sender;
299
+ txToSign.feePayer = new web3_js_1.PublicKey(sender);
292
300
  txToSign.recentBlockhash = blockhash;
293
301
  txToSign.addSignature(signer, buffer_1.Buffer.from(signatureString, "hex"));
294
302
  this.logger.debug("isSignatureValid(): Signed tx: ", txToSign);
@@ -353,10 +361,10 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
353
361
  async txsInitPayIn(swapData, timeout, prefix, signature, skipChecks, feeRate) {
354
362
  if (!skipChecks) {
355
363
  const [_, payStatus] = await Promise.all([
356
- (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError),
364
+ (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData.getOfferer(), swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError),
357
365
  (0, Utils_1.tryWithRetries)(() => this.program.getClaimHashStatus(swapData.getClaimHash()), this.retryPolicy)
358
366
  ]);
359
- if (payStatus !== base_1.SwapCommitStatus.NOT_COMMITED)
367
+ if (payStatus !== base_1.SwapCommitStateType.NOT_COMMITED)
360
368
  throw new base_1.SwapDataVerificationError("Invoice already being paid for or paid");
361
369
  }
362
370
  const [slotNumber, signatureStr] = signature.split(";");
@@ -393,7 +401,7 @@ class SwapInit extends SolanaSwapModule_1.SolanaSwapModule {
393
401
  */
394
402
  async txsInit(swapData, timeout, prefix, signature, skipChecks, feeRate) {
395
403
  if (!skipChecks) {
396
- await (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError);
404
+ await (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData.getClaimer(), swapData, timeout, prefix, signature, feeRate), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError);
397
405
  }
398
406
  const [slotNumber, signatureStr] = signature.split(";");
399
407
  const block = await (0, Utils_1.tryWithRetries)(() => this.root.Blocks.getParsedBlock(parseInt(slotNumber)), this.retryPolicy);
@@ -185,7 +185,6 @@ class SwapRefund extends SolanaSwapModule_1.SolanaSwapModule {
185
185
  throw new base_1.SwapDataVerificationError("ATA not initialized");
186
186
  if (feeRate == null)
187
187
  feeRate = await this.program.getRefundFeeRate(swapData);
188
- console.log("[SolanaSwapProgram] txsRefundsWithAuthorization: feeRate: ", feeRate);
189
188
  const signatureBuffer = buffer_1.Buffer.from(signature, "hex");
190
189
  const shouldUnwrap = this.shouldUnwrap(swapData);
191
190
  const action = await this.RefundWithSignature(swapData, timeout, prefix, signatureBuffer);
@@ -31,10 +31,10 @@ function onceAsync(executor) {
31
31
  exports.onceAsync = onceAsync;
32
32
  function getLogger(prefix) {
33
33
  return {
34
- debug: (msg, ...args) => console.debug(prefix + msg, ...args),
35
- info: (msg, ...args) => console.info(prefix + msg, ...args),
36
- warn: (msg, ...args) => console.warn(prefix + msg, ...args),
37
- error: (msg, ...args) => console.error(prefix + msg, ...args)
34
+ debug: (msg, ...args) => global.atomiqLogLevel >= 3 && console.debug(prefix + msg, ...args),
35
+ info: (msg, ...args) => global.atomiqLogLevel >= 2 && console.info(prefix + msg, ...args),
36
+ warn: (msg, ...args) => (global.atomiqLogLevel == null || global.atomiqLogLevel >= 1) && console.warn(prefix + msg, ...args),
37
+ error: (msg, ...args) => (global.atomiqLogLevel == null || global.atomiqLogLevel >= 0) && console.error(prefix + msg, ...args)
38
38
  };
39
39
  }
40
40
  exports.getLogger = getLogger;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/chain-solana",
3
- "version": "9.0.0",
3
+ "version": "10.0.0-dev.3",
4
4
  "description": "Solana specific base implementation",
5
5
  "main": "./dist/index.js",
6
6
  "types:": "./dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "author": "adambor",
23
23
  "license": "ISC",
24
24
  "dependencies": {
25
- "@atomiqlabs/base": "^9.0.0",
25
+ "@atomiqlabs/base": "^10.0.0-dev.2",
26
26
  "@noble/hashes": "^1.7.1",
27
27
  "bn.js": "5.2.1",
28
28
  "bs58": "4.0.1",
@@ -1,6 +1,13 @@
1
1
  import {BitcoinNetwork} from "@atomiqlabs/base";
2
2
 
3
3
  export const SolanaChains = {
4
+ //TODO: Not deployed yet
5
+ [BitcoinNetwork.TESTNET4]: {
6
+ addresses: {
7
+ swapContract: "11111111111111111111111111111111",
8
+ btcRelayContract: "11111111111111111111111111111111"
9
+ }
10
+ },
4
11
  [BitcoinNetwork.TESTNET]: {
5
12
  addresses: {
6
13
  swapContract: "4hfUykhqmD7ZRvNh1HuzVKEY7ToENixtdUKZspNDCrEM",
@@ -157,7 +157,6 @@ export class SolanaFees {
157
157
 
158
158
  if(request.ok) {
159
159
  const parsedResponse = await request.json();
160
- // console.log(parsedResponse);
161
160
  return parsedResponse.result;
162
161
  }
163
162
 
@@ -125,13 +125,10 @@ export class SolanaChainEvents extends SolanaChainEventsBrowser {
125
125
  const eventObject = this.getEventObjectFromTransaction(transaction);
126
126
  if(eventObject==null) return true;
127
127
 
128
- console.log("Instructions: ", eventObject.instructions);
129
- console.log("Events: ", eventObject.events);
130
-
131
128
  await this.processEvent(eventObject);
132
129
  return true;
133
130
  } catch (e) {
134
- console.error(e);
131
+ this.logger.error("fetchTxAndProcessEvent(): Error fetching transaction and processing event, signature: "+signature, e);
135
132
  return false;
136
133
  }
137
134
  }
@@ -150,7 +147,7 @@ export class SolanaChainEvents extends SolanaChainEventsBrowser {
150
147
  if(this.signaturesProcessing[signature]!=null) return;
151
148
  if(this.isSignatureProcessed(signature)) return;
152
149
 
153
- console.log("[Solana Events WebSocket] Process signature: ", signature);
150
+ this.logger.debug("getWsEventHandler("+name+"): Process signature: ", signature);
154
151
 
155
152
  this.signaturesProcessing[signature] = this.processEvent({
156
153
  events: [{name, data: data as any}],
@@ -158,7 +155,7 @@ export class SolanaChainEvents extends SolanaChainEventsBrowser {
158
155
  blockTime: Math.floor(Date.now()/1000),
159
156
  signature
160
157
  }).then(() => true).catch(e => {
161
- console.error(e);
158
+ this.logger.error("getWsEventHandler("+name+"): Error processing signature: "+signature, e);
162
159
  return false;
163
160
  });
164
161
  };
@@ -182,7 +179,7 @@ export class SolanaChainEvents extends SolanaChainEventsBrowser {
182
179
  }, "confirmed");
183
180
  //Check if newest returned signature (index 0) is older than the latest signature's slot, this is a sanity check
184
181
  if(fetched.length>0 && fetched[0].slot<lastProcessedSignature.slot) {
185
- console.log("[Solana Events POLL] Sanity check triggered, returned signature slot height is older than latest!");
182
+ this.logger.debug("getNewSignatures(): Sanity check triggered, returned signature slot height is older than latest!");
186
183
  return;
187
184
  }
188
185
  } else {
@@ -236,7 +233,7 @@ export class SolanaChainEvents extends SolanaChainEventsBrowser {
236
233
  }
237
234
  }
238
235
 
239
- console.log("[Solana Events POLL] Process signature: ", txSignature);
236
+ this.logger.debug("processSignatures(): Process signature: ", txSignature);
240
237
 
241
238
  const processPromise: Promise<boolean> = this.fetchTxAndProcessEvent(txSignature.signature);
242
239
  this.signaturesProcessing[txSignature.signature] = processPromise;
@@ -248,7 +245,7 @@ export class SolanaChainEvents extends SolanaChainEventsBrowser {
248
245
  delete this.signaturesProcessing[txSignature.signature];
249
246
  }
250
247
  } catch (e) {
251
- console.error(e);
248
+ this.logger.error("processSignatures(): Failed processing signatures: ", e);
252
249
  }
253
250
  return lastSuccessfulSignature;
254
251
  }
@@ -276,8 +273,7 @@ export class SolanaChainEvents extends SolanaChainEventsBrowser {
276
273
  let func;
277
274
  func = async () => {
278
275
  await this.checkEvents().catch(e => {
279
- console.error("Failed to fetch Sol log");
280
- console.error(e);
276
+ this.logger.error("setupHttpPolling(): Failed to fetch Solana log: ", e);
281
277
  });
282
278
  if(this.stopped) return;
283
279
  this.timeout = setTimeout(func, this.logFetchInterval);
@@ -211,7 +211,7 @@ export class SolanaChainEventsBrowser implements ChainEvents<SolanaSwapData> {
211
211
  blockTime: Math.floor(Date.now()/1000),
212
212
  signature
213
213
  }).then(() => true).catch(e => {
214
- console.error(e);
214
+ this.logger.error("wsEventHandler: Error when processing signature: "+signature, e);
215
215
  return false;
216
216
  });
217
217
  };
@@ -70,7 +70,7 @@ export class SolanaProgramEvents<IDL extends Idl> extends SolanaEvents {
70
70
  */
71
71
  public findInEvents<T>(
72
72
  topicKey: PublicKey,
73
- processor: (event: ProgramEvent<IDL>) => Promise<T>,
73
+ processor: (event: ProgramEvent<IDL>, info: ConfirmedSignatureInfo) => Promise<T>,
74
74
  abortSignal?: AbortSignal,
75
75
  logBatchSize?: number
76
76
  ): Promise<T> {
@@ -78,7 +78,7 @@ export class SolanaProgramEvents<IDL extends Idl> extends SolanaEvents {
78
78
  for(let data of signatures) {
79
79
  for(let event of await this.getEvents(data.signature)) {
80
80
  if(abortSignal!=null) abortSignal.throwIfAborted();
81
- const result: T = await processor(event);
81
+ const result: T = await processor(event, data);
82
82
  if(result!=null) return result;
83
83
  }
84
84
  }
@@ -1,23 +1,29 @@
1
1
  import {SolanaSwapData} from "./SolanaSwapData";
2
2
  import {IdlAccounts} from "@coral-xyz/anchor";
3
3
  import {
4
- Connection,
5
4
  PublicKey,
6
5
  } from "@solana/web3.js";
7
6
  import {sha256} from "@noble/hashes/sha2";
8
7
  import {SolanaBtcRelay} from "../btcrelay/SolanaBtcRelay";
9
8
  import * as programIdl from "./programIdl.json";
10
9
  import {
11
- IStorageManager, SwapContract, ChainSwapType, IntermediaryReputationType,
12
- SwapCommitStatus, TransactionConfirmationOptions, SignatureData, RelaySynchronizer, BigIntBufferUtils
10
+ IStorageManager,
11
+ SwapContract,
12
+ ChainSwapType,
13
+ IntermediaryReputationType,
14
+ TransactionConfirmationOptions,
15
+ SignatureData,
16
+ RelaySynchronizer,
17
+ BigIntBufferUtils,
18
+ SwapCommitState,
19
+ SwapCommitStateType, SwapNotCommitedState, SwapExpiredState, SwapPaidState
13
20
  } from "@atomiqlabs/base";
14
21
  import {SolanaBtcStoredHeader} from "../btcrelay/headers/SolanaBtcStoredHeader";
15
22
  import {
16
23
  getAssociatedTokenAddressSync,
17
24
  } from "@solana/spl-token";
18
- import {SolanaFees} from "../chain/modules/SolanaFees";
19
25
  import {SwapProgram} from "./programTypes";
20
- import {SolanaChainInterface, SolanaRetryPolicy} from "../chain/SolanaChainInterface";
26
+ import {SolanaChainInterface} from "../chain/SolanaChainInterface";
21
27
  import {SolanaProgramBase} from "../program/SolanaProgramBase";
22
28
  import {SolanaTx} from "../chain/modules/SolanaTransactions";
23
29
  import {SwapInit, SolanaPreFetchData, SolanaPreFetchVerification} from "./modules/SwapInit";
@@ -118,8 +124,8 @@ export class SolanaSwapProgram
118
124
  return this.Init.signSwapInitialization(signer, swapData, authorizationTimeout, preFetchedBlockData, feeRate);
119
125
  }
120
126
 
121
- isValidInitAuthorization(swapData: SolanaSwapData, {timeout, prefix, signature}, feeRate?: string, preFetchedData?: SolanaPreFetchVerification): Promise<Buffer> {
122
- return this.Init.isSignatureValid(swapData, timeout, prefix, signature, feeRate, preFetchedData);
127
+ isValidInitAuthorization(signer: string, swapData: SolanaSwapData, {timeout, prefix, signature}, feeRate?: string, preFetchedData?: SolanaPreFetchVerification): Promise<Buffer> {
128
+ return this.Init.isSignatureValid(signer, swapData, timeout, prefix, signature, feeRate, preFetchedData);
123
129
  }
124
130
 
125
131
  getInitAuthorizationExpiry(swapData: SolanaSwapData, {timeout, prefix, signature}, preFetchedData?: SolanaPreFetchVerification): Promise<number> {
@@ -245,7 +251,7 @@ export class SolanaSwapProgram
245
251
  * @param signer
246
252
  * @param data
247
253
  */
248
- async getCommitStatus(signer: string, data: SolanaSwapData): Promise<SwapCommitStatus> {
254
+ async getCommitStatus(signer: string, data: SolanaSwapData): Promise<SwapCommitState> {
249
255
  const escrowStateKey = this.SwapEscrowState(Buffer.from(data.paymentHash, "hex"));
250
256
  const [escrowState, isExpired] = await Promise.all([
251
257
  this.program.account.escrowState.fetchNullable(escrowStateKey) as Promise<IdlAccounts<SwapProgram>["escrowState"]>,
@@ -254,32 +260,47 @@ export class SolanaSwapProgram
254
260
 
255
261
  if(escrowState!=null) {
256
262
  if(data.correctPDA(escrowState)) {
257
- if(data.isOfferer(signer) && isExpired) return SwapCommitStatus.REFUNDABLE;
258
- return SwapCommitStatus.COMMITED;
263
+ if(data.isOfferer(signer) && isExpired) return {type: SwapCommitStateType.REFUNDABLE};
264
+ return {type: SwapCommitStateType.COMMITED};
259
265
  }
260
266
 
261
- if(data.isOfferer(signer) && isExpired) return SwapCommitStatus.EXPIRED;
262
- return SwapCommitStatus.NOT_COMMITED;
267
+ if(data.isOfferer(signer) && isExpired) return {type: SwapCommitStateType.EXPIRED};
268
+ return {type: SwapCommitStateType.NOT_COMMITED};
263
269
  }
264
270
 
265
271
  //Check if paid or what
266
- const status = await this.Events.findInEvents(escrowStateKey, async (event) => {
272
+ const status: SwapNotCommitedState | SwapExpiredState | SwapPaidState = await this.Events.findInEvents(escrowStateKey, async (event, info) => {
267
273
  if(event.name==="ClaimEvent") {
268
274
  if(!event.data.sequence.eq(data.sequence)) return null;
269
- return SwapCommitStatus.PAID;
275
+ return {
276
+ type: SwapCommitStateType.PAID,
277
+ getClaimTxId: () => Promise.resolve(info.signature),
278
+ getTxBlock: async () => {
279
+ return {
280
+ blockHeight: (await this.Chain.Blocks.getParsedBlock(info.slot)).blockHeight,
281
+ blockTime: info.blockTime
282
+ };
283
+ }
284
+ }
270
285
  }
271
286
  if(event.name==="RefundEvent") {
272
287
  if(!event.data.sequence.eq(data.sequence)) return null;
273
- if(isExpired) return SwapCommitStatus.EXPIRED;
274
- return SwapCommitStatus.NOT_COMMITED;
288
+ return {
289
+ type: isExpired ? SwapCommitStateType.EXPIRED : SwapCommitStateType.NOT_COMMITED,
290
+ getRefundTxId: () => Promise.resolve(info.signature),
291
+ getTxBlock: async () => {
292
+ return {
293
+ blockHeight: (await this.Chain.Blocks.getParsedBlock(info.slot)).blockHeight,
294
+ blockTime: info.blockTime
295
+ };
296
+ }
297
+ };
275
298
  }
276
299
  });
277
300
  if(status!=null) return status;
278
301
 
279
- if(isExpired) {
280
- return SwapCommitStatus.EXPIRED;
281
- }
282
- return SwapCommitStatus.NOT_COMMITED;
302
+ if(isExpired) return {type: SwapCommitStateType.EXPIRED};
303
+ return {type: SwapCommitStateType.NOT_COMMITED};
283
304
  }
284
305
 
285
306
  /**
@@ -287,15 +308,15 @@ export class SolanaSwapProgram
287
308
  *
288
309
  * @param claimHash
289
310
  */
290
- async getClaimHashStatus(claimHash: string): Promise<SwapCommitStatus> {
311
+ async getClaimHashStatus(claimHash: string): Promise<SwapCommitStateType> {
291
312
  const {paymentHash} = fromClaimHash(claimHash);
292
313
  const escrowStateKey = this.SwapEscrowState(Buffer.from(paymentHash, "hex"));
293
314
  const abortController = new AbortController();
294
315
 
295
316
  //Start fetching events before checking escrow PDA, this call is used when quoting, so saving 100ms here helps a lot!
296
317
  const eventsPromise = this.Events.findInEvents(escrowStateKey, async (event) => {
297
- if(event.name==="ClaimEvent") return SwapCommitStatus.PAID;
298
- if(event.name==="RefundEvent") return SwapCommitStatus.NOT_COMMITED;
318
+ if(event.name==="ClaimEvent") return SwapCommitStateType.PAID;
319
+ if(event.name==="RefundEvent") return SwapCommitStateType.NOT_COMMITED;
299
320
  }, abortController.signal).catch(e => {
300
321
  abortController.abort(e)
301
322
  return null;
@@ -305,7 +326,7 @@ export class SolanaSwapProgram
305
326
  abortController.signal.throwIfAborted();
306
327
  if(escrowState!=null) {
307
328
  abortController.abort();
308
- return SwapCommitStatus.COMMITED;
329
+ return SwapCommitStateType.COMMITED;
309
330
  }
310
331
 
311
332
  //Check if paid or what
@@ -313,7 +334,7 @@ export class SolanaSwapProgram
313
334
  abortController.signal.throwIfAborted();
314
335
  if(eventsStatus!=null) return eventsStatus;
315
336
 
316
- return SwapCommitStatus.NOT_COMMITED;
337
+ return SwapCommitStateType.NOT_COMMITED;
317
338
  }
318
339
 
319
340
  /**
@@ -445,10 +466,12 @@ export class SolanaSwapProgram
445
466
  return this.Refund.txsRefundWithAuthorization(swapData,timeout,prefix,signature,check,initAta,feeRate);
446
467
  }
447
468
 
448
- txsInit(swapData: SolanaSwapData, {timeout, prefix, signature}, skipChecks?: boolean, feeRate?: string): Promise<SolanaTx[]> {
469
+ txsInit(sender: string, swapData: SolanaSwapData, {timeout, prefix, signature}, skipChecks?: boolean, feeRate?: string): Promise<SolanaTx[]> {
449
470
  if(swapData.isPayIn()) {
471
+ if(!swapData.isOfferer(sender)) throw new Error("Only offerer can create payIn=true swap");
450
472
  return this.Init.txsInitPayIn(swapData, timeout, prefix, signature, skipChecks, feeRate);
451
473
  } else {
474
+ if(!swapData.isClaimer(sender)) throw new Error("Only claimer can create payIn=false swap");
452
475
  return this.Init.txsInit(swapData, timeout, prefix, signature, skipChecks, feeRate);
453
476
  }
454
477
  }
@@ -548,7 +571,7 @@ export class SolanaSwapProgram
548
571
  if(!signer.getPublicKey().equals(swapData.claimer)) throw new Error("Invalid signer provided!");
549
572
  }
550
573
 
551
- const result = await this.txsInit(swapData, signature, skipChecks, txOptions?.feeRate);
574
+ const result = await this.txsInit(signer.getAddress(), swapData, signature, skipChecks, txOptions?.feeRate);
552
575
 
553
576
  const [txSignature] = await this.Chain.sendAndConfirm(signer, result, txOptions?.waitForConfirmation, txOptions?.abortSignal);
554
577
 
@@ -565,7 +588,7 @@ export class SolanaSwapProgram
565
588
  ): Promise<string[]> {
566
589
  if(!signer.getPublicKey().equals(swapData.claimer)) throw new Error("Invalid signer provided!");
567
590
 
568
- const txsCommit = await this.txsInit(swapData, signature, skipChecks, txOptions?.feeRate);
591
+ const txsCommit = await this.txsInit(signer.getAddress(), swapData, signature, skipChecks, txOptions?.feeRate);
569
592
  const txsClaim = await this.Claim.txsClaimWithSecret(signer.getPublicKey(), swapData, secret, true, false, txOptions?.feeRate, true);
570
593
 
571
594
  return await this.Chain.sendAndConfirm(signer, txsCommit.concat(txsClaim), txOptions?.waitForConfirmation, txOptions?.abortSignal);
@@ -634,28 +657,28 @@ export class SolanaSwapProgram
634
657
  /**
635
658
  * Get the estimated solana fee of the commit transaction
636
659
  */
637
- getCommitFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
660
+ getCommitFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
638
661
  return this.Init.getInitFee(swapData, feeRate);
639
662
  }
640
663
 
641
664
  /**
642
665
  * Get the estimated solana fee of the commit transaction, without any deposits
643
666
  */
644
- getRawCommitFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
667
+ getRawCommitFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
645
668
  return this.Init.getRawInitFee(swapData, feeRate);
646
669
  }
647
670
 
648
671
  /**
649
672
  * Get the estimated solana transaction fee of the refund transaction
650
673
  */
651
- getRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
674
+ getRefundFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
652
675
  return this.Refund.getRefundFee(swapData, feeRate);
653
676
  }
654
677
 
655
678
  /**
656
679
  * Get the estimated solana transaction fee of the refund transaction
657
680
  */
658
- getRawRefundFee(swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
681
+ getRawRefundFee(signer: string, swapData: SolanaSwapData, feeRate?: string): Promise<bigint> {
659
682
  return this.Refund.getRawRefundFee(swapData, feeRate);
660
683
  }
661
684
 
@@ -1,5 +1,9 @@
1
1
  import {ParsedAccountsModeBlockResponse, PublicKey, SystemProgram, Transaction} from "@solana/web3.js";
2
- import {SignatureVerificationError, SwapCommitStatus, SwapDataVerificationError} from "@atomiqlabs/base";
2
+ import {
3
+ SignatureVerificationError,
4
+ SwapCommitStateType,
5
+ SwapDataVerificationError
6
+ } from "@atomiqlabs/base";
3
7
  import {SolanaSwapData} from "../SolanaSwapData";
4
8
  import {SolanaAction} from "../../chain/SolanaAction";
5
9
  import {
@@ -335,6 +339,7 @@ export class SwapInit extends SolanaSwapModule {
335
339
  /**
336
340
  * Checks whether the provided signature data is valid, using preFetchedData if provided and still valid
337
341
  *
342
+ * @param sender
338
343
  * @param swapData
339
344
  * @param timeout
340
345
  * @param prefix
@@ -344,6 +349,7 @@ export class SwapInit extends SolanaSwapModule {
344
349
  * @public
345
350
  */
346
351
  public async isSignatureValid(
352
+ sender: string,
347
353
  swapData: SolanaSwapData,
348
354
  timeout: string,
349
355
  prefix: string,
@@ -351,7 +357,12 @@ export class SwapInit extends SolanaSwapModule {
351
357
  feeRate?: string,
352
358
  preFetchedData?: SolanaPreFetchVerification
353
359
  ): Promise<Buffer> {
354
- const sender = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
360
+ if(swapData.isPayIn()) {
361
+ if(!swapData.isOfferer(sender)) throw new SignatureVerificationError("Sender needs to be offerer in payIn=true swaps");
362
+ } else {
363
+ if(!swapData.isClaimer(sender)) throw new SignatureVerificationError("Sender needs to be claimer in payIn=false swaps");
364
+ }
365
+
355
366
  const signer = swapData.isPayIn() ? swapData.claimer : swapData.offerer;
356
367
 
357
368
  if(!swapData.isPayIn() && await this.program.isExpired(sender.toString(), swapData)) {
@@ -377,7 +388,7 @@ export class SwapInit extends SolanaSwapModule {
377
388
  if(slotsLeft<0) throw new SignatureVerificationError("Authorization expired!");
378
389
 
379
390
  const txToSign = await this.getTxToSign(swapData, timeout, feeRate);
380
- txToSign.feePayer = sender;
391
+ txToSign.feePayer = new PublicKey(sender);
381
392
  txToSign.recentBlockhash = blockhash;
382
393
  txToSign.addSignature(signer, Buffer.from(signatureString, "hex"));
383
394
  this.logger.debug("isSignatureValid(): Signed tx: ",txToSign);
@@ -466,12 +477,12 @@ export class SwapInit extends SolanaSwapModule {
466
477
  if(!skipChecks) {
467
478
  const [_, payStatus] = await Promise.all([
468
479
  tryWithRetries(
469
- () => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate),
480
+ () => this.isSignatureValid(swapData.getOfferer(), swapData, timeout, prefix, signature, feeRate),
470
481
  this.retryPolicy, (e) => e instanceof SignatureVerificationError
471
482
  ),
472
483
  tryWithRetries(() => this.program.getClaimHashStatus(swapData.getClaimHash()), this.retryPolicy)
473
484
  ]);
474
- if(payStatus!==SwapCommitStatus.NOT_COMMITED) throw new SwapDataVerificationError("Invoice already being paid for or paid");
485
+ if(payStatus!==SwapCommitStateType.NOT_COMMITED) throw new SwapDataVerificationError("Invoice already being paid for or paid");
475
486
  }
476
487
 
477
488
  const [slotNumber, signatureStr] = signature.split(";");
@@ -522,7 +533,7 @@ export class SwapInit extends SolanaSwapModule {
522
533
  public async txsInit(swapData: SolanaSwapData, timeout: string, prefix: string, signature: string, skipChecks?: boolean, feeRate?: string): Promise<SolanaTx[]> {
523
534
  if(!skipChecks) {
524
535
  await tryWithRetries(
525
- () => this.isSignatureValid(swapData, timeout, prefix, signature, feeRate),
536
+ () => this.isSignatureValid(swapData.getClaimer(), swapData, timeout, prefix, signature, feeRate),
526
537
  this.retryPolicy,
527
538
  (e) => e instanceof SignatureVerificationError
528
539
  );
@@ -249,7 +249,6 @@ export class SwapRefund extends SolanaSwapModule {
249
249
  if(shouldInitAta && !initAta) throw new SwapDataVerificationError("ATA not initialized");
250
250
 
251
251
  if(feeRate==null) feeRate = await this.program.getRefundFeeRate(swapData);
252
- console.log("[SolanaSwapProgram] txsRefundsWithAuthorization: feeRate: ", feeRate);
253
252
 
254
253
  const signatureBuffer = Buffer.from(signature, "hex");
255
254
 
@@ -28,10 +28,10 @@ export function onceAsync<T>(executor: () => Promise<T>): () => Promise<T> {
28
28
 
29
29
  export function getLogger(prefix: string) {
30
30
  return {
31
- debug: (msg, ...args) => console.debug(prefix+msg, ...args),
32
- info: (msg, ...args) => console.info(prefix+msg, ...args),
33
- warn: (msg, ...args) => console.warn(prefix+msg, ...args),
34
- error: (msg, ...args) => console.error(prefix+msg, ...args)
31
+ debug: (msg, ...args) => global.atomiqLogLevel >= 3 && console.debug(prefix+msg, ...args),
32
+ info: (msg, ...args) => global.atomiqLogLevel >= 2 && console.info(prefix+msg, ...args),
33
+ warn: (msg, ...args) => (global.atomiqLogLevel==null || global.atomiqLogLevel >= 1) && console.warn(prefix+msg, ...args),
34
+ error: (msg, ...args) => (global.atomiqLogLevel==null || global.atomiqLogLevel >= 0) && console.error(prefix+msg, ...args)
35
35
  };
36
36
  }
37
37