@atomiqlabs/lp-lib 15.0.13 → 16.0.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 (66) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +2 -0
  3. package/dist/info/InfoHandler.js +0 -3
  4. package/dist/plugins/IPlugin.d.ts +2 -2
  5. package/dist/plugins/PluginManager.d.ts +2 -2
  6. package/dist/storagemanager/IntermediaryStorageManager.d.ts +1 -0
  7. package/dist/storagemanager/IntermediaryStorageManager.js +9 -2
  8. package/dist/storagemanager/StorageManager.d.ts +1 -0
  9. package/dist/storagemanager/StorageManager.js +9 -2
  10. package/dist/swaps/SwapHandler.d.ts +4 -10
  11. package/dist/swaps/SwapHandler.js +4 -13
  12. package/dist/swaps/assertions/FromBtcAmountAssertions.d.ts +2 -2
  13. package/dist/swaps/assertions/FromBtcAmountAssertions.js +13 -5
  14. package/dist/swaps/escrow/EscrowHandlerSwap.js +2 -2
  15. package/dist/swaps/escrow/FromBtcBaseSwapHandler.d.ts +2 -1
  16. package/dist/swaps/escrow/FromBtcBaseSwapHandler.js +8 -5
  17. package/dist/swaps/escrow/frombtc_abstract/FromBtcAbs.js +2 -2
  18. package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnAbs.js +11 -13
  19. package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +1 -0
  20. package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnSwapAbs.js +3 -0
  21. package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.d.ts +111 -0
  22. package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.js +682 -0
  23. package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAutoSwap.d.ts +55 -0
  24. package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAutoSwap.js +120 -0
  25. package/dist/swaps/escrow/tobtc_abstract/ToBtcAbs.d.ts +0 -2
  26. package/dist/swaps/escrow/tobtc_abstract/ToBtcAbs.js +44 -27
  27. package/dist/swaps/escrow/tobtcln_abstract/ToBtcLnAbs.js +12 -10
  28. package/dist/swaps/spv_vault_swap/SpvVault.d.ts +2 -3
  29. package/dist/swaps/spv_vault_swap/SpvVault.js +2 -2
  30. package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.js +10 -8
  31. package/dist/swaps/spv_vault_swap/SpvVaults.d.ts +4 -9
  32. package/dist/swaps/spv_vault_swap/SpvVaults.js +114 -80
  33. package/dist/swaps/trusted/frombtc_trusted/FromBtcTrusted.js +3 -3
  34. package/dist/swaps/trusted/frombtcln_trusted/FromBtcLnTrusted.js +14 -17
  35. package/dist/utils/Utils.d.ts +7 -7
  36. package/dist/utils/Utils.js +12 -11
  37. package/dist/utils/paramcoders/server/ServerParamDecoder.js +8 -6
  38. package/dist/wallets/IBitcoinWallet.d.ts +7 -0
  39. package/package.json +3 -3
  40. package/src/index.ts +2 -0
  41. package/src/info/InfoHandler.ts +0 -6
  42. package/src/plugins/IPlugin.ts +2 -2
  43. package/src/plugins/PluginManager.ts +2 -2
  44. package/src/storagemanager/IntermediaryStorageManager.ts +11 -2
  45. package/src/storagemanager/StorageManager.ts +12 -2
  46. package/src/swaps/SwapHandler.ts +6 -17
  47. package/src/swaps/assertions/FromBtcAmountAssertions.ts +16 -8
  48. package/src/swaps/escrow/EscrowHandlerSwap.ts +2 -2
  49. package/src/swaps/escrow/FromBtcBaseSwapHandler.ts +8 -5
  50. package/src/swaps/escrow/frombtc_abstract/FromBtcAbs.ts +2 -2
  51. package/src/swaps/escrow/frombtcln_abstract/FromBtcLnAbs.ts +11 -12
  52. package/src/swaps/escrow/frombtcln_abstract/FromBtcLnSwapAbs.ts +4 -0
  53. package/src/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.ts +847 -0
  54. package/src/swaps/escrow/frombtcln_autoinit/FromBtcLnAutoSwap.ts +196 -0
  55. package/src/swaps/escrow/tobtc_abstract/ToBtcAbs.ts +55 -36
  56. package/src/swaps/escrow/tobtcln_abstract/ToBtcLnAbs.ts +19 -15
  57. package/src/swaps/spv_vault_swap/SpvVault.ts +3 -3
  58. package/src/swaps/spv_vault_swap/SpvVaultSwapHandler.ts +10 -8
  59. package/src/swaps/spv_vault_swap/SpvVaults.ts +130 -91
  60. package/src/swaps/trusted/frombtc_trusted/FromBtcTrusted.ts +3 -3
  61. package/src/swaps/trusted/frombtcln_trusted/FromBtcLnTrusted.ts +13 -16
  62. package/src/utils/Utils.ts +19 -17
  63. package/src/utils/paramcoders/server/ServerParamDecoder.ts +9 -6
  64. package/src/wallets/IBitcoinWallet.ts +8 -0
  65. package/dist/wallets/ISpvVaultWallet.d.ts +0 -42
  66. package/dist/wallets/ISpvVaultWallet.js +0 -2
@@ -9,20 +9,29 @@ const btc_signer_1 = require("@scure/btc-signer");
9
9
  const BitcoinUtils_1 = require("../../utils/BitcoinUtils");
10
10
  exports.VAULT_DUST_AMOUNT = 600;
11
11
  const VAULT_INIT_CONFIRMATIONS = 2;
12
+ const MAX_PARALLEL_VAULTS_OPENING = 10;
12
13
  class SpvVaults {
13
- constructor(vaultStorage, bitcoin, vaultSigner, bitcoinRpc, getChain, config) {
14
- this.logger = {
15
- debug: (msg, ...args) => console.debug("SpvVaults: " + msg, ...args),
16
- info: (msg, ...args) => console.info("SpvVaults: " + msg, ...args),
17
- warn: (msg, ...args) => console.warn("SpvVaults: " + msg, ...args),
18
- error: (msg, ...args) => console.error("SpvVaults: " + msg, ...args)
19
- };
14
+ constructor(vaultStorage, bitcoin, vaultSigner, bitcoinRpc, chains, config) {
15
+ this.logger = (0, Utils_1.getLogger)("SpvVaults: ");
20
16
  this.vaultStorage = vaultStorage;
21
17
  this.bitcoin = bitcoin;
22
18
  this.vaultSigner = vaultSigner;
23
19
  this.bitcoinRpc = bitcoinRpc;
24
- this.getChain = getChain;
20
+ this.chains = chains;
25
21
  this.config = config;
22
+ for (let chainId in chains.chains) {
23
+ const { chainInterface } = chains.chains[chainId];
24
+ chainInterface.onBeforeTxReplace(async (oldTx, oldTxId, newTx, newTxId) => {
25
+ for (let key in this.vaultStorage.data) {
26
+ const vaultData = this.vaultStorage.data[key];
27
+ if (vaultData.scOpenTxs != null && vaultData.scOpenTxs[oldTxId] != null) {
28
+ vaultData.scOpenTxs[newTxId] = newTx;
29
+ await this.saveVault(vaultData);
30
+ break;
31
+ }
32
+ }
33
+ });
34
+ }
26
35
  }
27
36
  async processDepositEvent(vault, event) {
28
37
  vault.update(event);
@@ -51,7 +60,7 @@ class SpvVaults {
51
60
  await this.saveVault(vault);
52
61
  }
53
62
  async createVaults(chainId, count, token, confirmations = 2, feeRate) {
54
- const { signer, chainInterface, tokenMultipliers, spvVaultContract } = this.getChain(chainId);
63
+ const { signer, chainInterface, tokenMultipliers, spvVaultContract } = this.chains.chains[chainId];
55
64
  const signerAddress = signer.getAddress();
56
65
  //Check vaultId of the latest saved vault
57
66
  let latestVaultId = -1n;
@@ -71,49 +80,54 @@ class SpvVaults {
71
80
  const address = await this.vaultSigner.getAddress(chainId, vaultId);
72
81
  vaultAddreses.push({ vaultId, address });
73
82
  }
74
- //Construct transaction
75
- const txResult = await this.bitcoin.getSignedMultiTransaction(vaultAddreses.map(val => {
76
- return { address: val.address, amount: exports.VAULT_DUST_AMOUNT };
77
- }), feeRate);
78
83
  const nativeToken = chainInterface.getNativeCurrencyAddress();
79
- const vaults = await Promise.all(vaultAddreses.map(async (val, index) => {
80
- const vaultData = await spvVaultContract.createVaultData(signerAddress, val.vaultId, txResult.txId + ":" + index, confirmations, [
81
- { token, multiplier: tokenMultipliers?.[token] ?? 1n },
82
- { token: nativeToken, multiplier: tokenMultipliers?.[nativeToken] ?? 1n }
83
- ]);
84
- return new SpvVault_1.SpvVault(chainId, vaultData, val.address);
85
- }));
86
- //Save vaults
87
- if (this.vaultStorage.saveDataArr != null) {
88
- await this.vaultStorage.saveDataArr(vaults.map(val => {
89
- return { id: val.getIdentifier(), object: val };
84
+ let txId = null;
85
+ let vaults = null;
86
+ await this.bitcoin.execute(async () => {
87
+ //Construct transaction
88
+ const txResult = await this.bitcoin.getSignedMultiTransaction(vaultAddreses.map(val => {
89
+ return { address: val.address, amount: exports.VAULT_DUST_AMOUNT };
90
+ }), feeRate);
91
+ vaults = await Promise.all(vaultAddreses.map(async (val, index) => {
92
+ const vaultData = await spvVaultContract.createVaultData(signerAddress, val.vaultId, txResult.txId + ":" + index, confirmations, [
93
+ { token, multiplier: tokenMultipliers?.[token] ?? 1n },
94
+ { token: nativeToken, multiplier: tokenMultipliers?.[nativeToken] ?? 1n }
95
+ ]);
96
+ return new SpvVault_1.SpvVault(chainId, vaultData, val.address);
90
97
  }));
91
- }
92
- else {
93
- for (let vault of vaults) {
94
- await this.vaultStorage.saveData(vault.getIdentifier(), vault);
98
+ //Save vaults
99
+ if (this.vaultStorage.saveDataArr != null) {
100
+ await this.vaultStorage.saveDataArr(vaults.map(val => {
101
+ return { id: val.getIdentifier(), object: val };
102
+ }));
95
103
  }
96
- }
97
- //Send bitcoin tx
98
- await this.bitcoin.sendRawTransaction(txResult.raw);
99
- this.logger.info("createVaults(): Funding " + count + " vaults, bitcoin txId: " + txResult.txId);
104
+ else {
105
+ for (let vault of vaults) {
106
+ await this.vaultStorage.saveData(vault.getIdentifier(), vault);
107
+ }
108
+ }
109
+ //Send bitcoin tx
110
+ await this.bitcoin.sendRawTransaction(txResult.raw);
111
+ txId = txResult.txId;
112
+ });
113
+ this.logger.info("createVaults(): Funding " + count + " vaults, bitcoin txId: " + txId);
100
114
  return {
101
115
  vaultsCreated: vaults.map(val => val.data.getVaultId()),
102
- btcTxId: txResult.txId
116
+ btcTxId: txId
103
117
  };
104
118
  }
105
119
  async listVaults(chainId, token) {
106
120
  return Object.keys(this.vaultStorage.data)
107
121
  .map(key => this.vaultStorage.data[key])
108
122
  .filter(val => chainId == null ? true : val.chainId === chainId)
109
- .filter(val => val.data.getOwner() === this.getChain(val.chainId)?.signer?.getAddress())
123
+ .filter(val => val.data.getOwner() === this.chains.chains[val.chainId]?.signer?.getAddress())
110
124
  .filter(val => token == null ? true : val.data.getTokenData()[0].token === token);
111
125
  }
112
126
  async fundVault(vault, tokenAmounts) {
113
127
  if (vault.state !== SpvVault_1.SpvVaultState.OPENED)
114
128
  throw new Error("Vault not opened!");
115
129
  this.logger.info("fundVault(): Depositing tokens to the vault " + vault.data.getVaultId().toString(10) + ", amounts: " + tokenAmounts.map(val => val.toString(10)).join(", "));
116
- const { signer, spvVaultContract } = this.getChain(vault.chainId);
130
+ const { signer, spvVaultContract } = this.chains.chains[vault.chainId];
117
131
  const txId = await spvVaultContract.deposit(signer, vault.data, tokenAmounts, { waitForConfirmation: true });
118
132
  this.logger.info("fundVault(): Tokens deposited to vault " + vault.data.getVaultId().toString(10) + ", amounts: " + tokenAmounts.map(val => val.toString(10)).join(", ") + ", txId: " + txId);
119
133
  return txId;
@@ -127,7 +141,7 @@ class SpvVaults {
127
141
  });
128
142
  if (!vault.isReady())
129
143
  throw new Error("Vault not ready, wait for the latest swap to get at least 1 confirmation!");
130
- const { signer, spvVaultContract } = this.getChain(vault.chainId);
144
+ const { signer, spvVaultContract } = this.chains.chains[vault.chainId];
131
145
  const latestUtxo = vault.getLatestUtxo();
132
146
  const [txId, voutStr] = latestUtxo.split(":");
133
147
  const opReturnData = spvVaultContract.toOpReturnData(signer.getAddress(), tokenAmounts);
@@ -163,32 +177,36 @@ class SpvVaults {
163
177
  amount: 0n,
164
178
  script: opReturnScript
165
179
  });
166
- psbt = await this.bitcoin.fundPsbt(psbt, feeRate);
167
- if (psbt.inputsLength < 2)
168
- throw new Error("PSBT needs at least 2 inputs!");
169
- psbt.updateInput(0, { sequence: 0x80000000 });
170
- psbt.updateInput(1, { sequence: 0x80000000 });
171
- psbt = await this.vaultSigner.signPsbt(vault.chainId, vault.data.getVaultId(), psbt, [0]);
172
- const res = await this.bitcoin.signPsbt(psbt);
173
- const parsedTransaction = await this.bitcoinRpc.parseTransaction(res.raw);
174
- const withdrawalData = await spvVaultContract.getWithdrawalData(parsedTransaction);
175
- if (withdrawalData.getSpentVaultUtxo() !== vault.getLatestUtxo()) {
176
- throw new Error("Latest vault UTXO already spent! Please try again later.");
177
- }
178
- withdrawalData.sending = true;
179
- vault.addWithdrawal(withdrawalData);
180
- await this.saveVault(vault);
181
- try {
182
- await this.bitcoin.sendRawTransaction(res.raw);
183
- withdrawalData.sending = false;
184
- }
185
- catch (e) {
186
- withdrawalData.sending = false;
187
- vault.removeWithdrawal(withdrawalData);
180
+ let withdrawalTxId = null;
181
+ await this.bitcoin.execute(async () => {
182
+ psbt = await this.bitcoin.fundPsbt(psbt, feeRate);
183
+ if (psbt.inputsLength < 2)
184
+ throw new Error("PSBT needs at least 2 inputs!");
185
+ psbt.updateInput(0, { sequence: 0x80000000 });
186
+ psbt.updateInput(1, { sequence: 0x80000000 });
187
+ psbt = await this.vaultSigner.signPsbt(vault.chainId, vault.data.getVaultId(), psbt, [0]);
188
+ const res = await this.bitcoin.signPsbt(psbt);
189
+ withdrawalTxId = res.txId;
190
+ const parsedTransaction = await this.bitcoinRpc.parseTransaction(res.raw);
191
+ const withdrawalData = await spvVaultContract.getWithdrawalData(parsedTransaction);
192
+ if (withdrawalData.getSpentVaultUtxo() !== vault.getLatestUtxo()) {
193
+ throw new Error("Latest vault UTXO already spent! Please try again later.");
194
+ }
195
+ withdrawalData.sending = true;
196
+ vault.addWithdrawal(withdrawalData);
188
197
  await this.saveVault(vault);
189
- throw e;
190
- }
191
- return res.txId;
198
+ try {
199
+ await this.bitcoin.sendRawTransaction(res.raw);
200
+ withdrawalData.sending = false;
201
+ }
202
+ catch (e) {
203
+ withdrawalData.sending = false;
204
+ vault.removeWithdrawal(withdrawalData);
205
+ await this.saveVault(vault);
206
+ throw e;
207
+ }
208
+ });
209
+ return withdrawalTxId;
192
210
  }
193
211
  /**
194
212
  * Call this to check whether some of the previously replaced transactions got re-introduced to the mempool
@@ -197,7 +215,7 @@ class SpvVaults {
197
215
  * @param save
198
216
  */
199
217
  async checkVaultReplacedTransactions(vault, save) {
200
- const { spvVaultContract } = this.getChain(vault.chainId);
218
+ const { spvVaultContract } = this.chains.chains[vault.chainId];
201
219
  const initialVaultWithdrawalCount = vault.data.getWithdrawalCount();
202
220
  let latestWithdrawalIndex = initialVaultWithdrawalCount;
203
221
  const newPendingTxns = [];
@@ -276,8 +294,9 @@ class SpvVaults {
276
294
  async checkVaults() {
277
295
  const vaults = Object.keys(this.vaultStorage.data).map(key => this.vaultStorage.data[key]);
278
296
  const claimWithdrawals = [];
297
+ let promises = [];
279
298
  for (let vault of vaults) {
280
- const { signer, spvVaultContract, chainInterface } = this.getChain(vault.chainId);
299
+ const { signer, spvVaultContract, chainInterface } = this.chains.chains[vault.chainId];
281
300
  if (vault.data.getOwner() !== signer.getAddress())
282
301
  continue;
283
302
  if (vault.state === SpvVault_1.SpvVaultState.BTC_INITIATED) {
@@ -295,30 +314,45 @@ class SpvVaults {
295
314
  }
296
315
  if (vault.state === SpvVault_1.SpvVaultState.BTC_CONFIRMED) {
297
316
  //Check if open txs were sent already
298
- if (vault.scOpenTx != null) {
317
+ if (vault.scOpenTxs != null) {
299
318
  //Check if confirmed
300
- const status = await chainInterface.getTxStatus(vault.scOpenTx.rawTx);
301
- if (status === "pending")
302
- return;
303
- if (status === "success") {
304
- vault.state = SpvVault_1.SpvVaultState.OPENED;
305
- await this.saveVault(vault);
306
- return;
319
+ let _continue = false;
320
+ for (let txId in vault.scOpenTxs) {
321
+ const tx = vault.scOpenTxs[txId];
322
+ const status = await chainInterface.getTxStatus(tx);
323
+ if (status === "pending") {
324
+ _continue = true;
325
+ break;
326
+ }
327
+ if (status === "success") {
328
+ vault.state = SpvVault_1.SpvVaultState.OPENED;
329
+ await this.saveVault(vault);
330
+ _continue = true;
331
+ break;
332
+ }
307
333
  }
334
+ if (_continue)
335
+ continue;
308
336
  }
309
337
  const txs = await spvVaultContract.txsOpen(signer.getAddress(), vault.data);
310
338
  let numTx = 0;
311
- const txIds = await chainInterface.sendAndConfirm(signer, txs, true, undefined, false, async (txId, rawTx) => {
339
+ promises.push(chainInterface.sendAndConfirm(signer, txs, true, undefined, true, async (txId, rawTx) => {
312
340
  numTx++;
313
341
  if (numTx === txs.length) {
314
342
  //Final tx
315
- vault.scOpenTx = { txId, rawTx };
343
+ vault.scOpenTxs = { [txId]: rawTx };
316
344
  await this.saveVault(vault);
317
345
  }
318
- });
319
- this.logger.info("checkVaults(): Vault ID " + vault.data.getVaultId().toString(10) + " opened on " + vault.chainId + " txId: " + txIds.join(", "));
320
- vault.state = SpvVault_1.SpvVaultState.OPENED;
321
- await this.saveVault(vault);
346
+ }).then(txIds => {
347
+ this.logger.info("checkVaults(): Vault ID " + vault.data.getVaultId().toString(10) + " opened on " + vault.chainId + " txId: " + txIds.join(", "));
348
+ vault.state = SpvVault_1.SpvVaultState.OPENED;
349
+ return this.saveVault(vault);
350
+ }));
351
+ if (promises.length >= MAX_PARALLEL_VAULTS_OPENING) {
352
+ await Promise.all(promises);
353
+ promises = [];
354
+ }
355
+ continue;
322
356
  }
323
357
  if (vault.state === SpvVault_1.SpvVaultState.OPENED) {
324
358
  let changed = await this.checkVaultReplacedTransactions(vault);
@@ -379,7 +413,7 @@ class SpvVaults {
379
413
  }
380
414
  }
381
415
  async claimWithdrawals(vault, withdrawal) {
382
- const { signer, spvVaultContract } = this.getChain(vault.chainId);
416
+ const { signer, spvVaultContract } = this.chains.chains[vault.chainId];
383
417
  try {
384
418
  const txId = await spvVaultContract.claim(signer, vault.data, withdrawal.map(tx => {
385
419
  return { tx };
@@ -407,7 +441,7 @@ class SpvVaults {
407
441
  * @protected
408
442
  */
409
443
  async findVaultForSwap(chainIdentifier, totalSats, token, amount, gasToken, gasTokenAmount) {
410
- const { signer } = this.getChain(chainIdentifier);
444
+ const { signer } = this.chains.chains[chainIdentifier];
411
445
  const pluginResponse = await PluginManager_1.PluginManager.onVaultSelection(chainIdentifier, totalSats, { token, amount }, { token: gasToken, amount: gasTokenAmount });
412
446
  if (pluginResponse != null) {
413
447
  AmountAssertions_1.AmountAssertions.handlePluginErrorResponses(pluginResponse);
@@ -442,7 +476,7 @@ class SpvVaults {
442
476
  async startVaultsWatchdog() {
443
477
  let rerun;
444
478
  rerun = async () => {
445
- await this.checkVaults().catch(e => console.error(e));
479
+ await this.checkVaults().catch(e => this.logger.error("startVaultsWatchdog(): Error when periodically checking SPV vaults: ", e));
446
480
  setTimeout(rerun, this.config.vaultsCheckInterval);
447
481
  };
448
482
  await rerun();
@@ -334,7 +334,7 @@ class FromBtcTrusted extends SwapHandler_1.SwapHandler {
334
334
  const getAddress = (0, Utils_1.expressHandlerWrapper)(async (req, res) => {
335
335
  var _a;
336
336
  const metadata = { request: {}, times: {} };
337
- const chainIdentifier = req.query.chain ?? this.chains.default;
337
+ const chainIdentifier = req.query.chain;
338
338
  const { chainInterface, signer } = this.getChain(chainIdentifier);
339
339
  metadata.times.requestReceived = Date.now();
340
340
  /**
@@ -347,7 +347,7 @@ class FromBtcTrusted extends SwapHandler_1.SwapHandler {
347
347
  const parsedBody = (0, SchemaVerifier_1.verifySchema)(req.query, {
348
348
  address: (val) => val != null &&
349
349
  typeof (val) === "string" &&
350
- chainInterface.isValidAddress(val) ? val : null,
350
+ chainInterface.isValidAddress(val, true) ? val : null,
351
351
  refundAddress: (val) => val == null ? "" :
352
352
  typeof (val) === "string" &&
353
353
  this.isValidBitcoinAddress(val) ? val : null,
@@ -618,7 +618,7 @@ class FromBtcTrusted extends SwapHandler_1.SwapHandler {
618
618
  async startDoubleSpendWatchdog() {
619
619
  let rerun;
620
620
  rerun = async () => {
621
- await this.checkDoubleSpends().catch(e => console.error(e));
621
+ await this.checkDoubleSpends().catch(e => this.logger.error("startDoubleSpendWatchdog(): Error when checking double spends: ", e));
622
622
  setTimeout(rerun, this.config.doubleSpendCheckInterval);
623
623
  };
624
624
  await rerun();
@@ -53,7 +53,7 @@ class FromBtcLnTrusted extends SwapHandler_1.SwapHandler {
53
53
  this.swapLogger.debug(invoiceData, "subscribeToInvoice(): invoice_updated: ", invoice);
54
54
  if (invoice.status !== "held")
55
55
  return;
56
- this.htlcReceived(invoiceData, invoice).catch(e => console.error(e));
56
+ this.htlcReceived(invoiceData, invoice).catch(e => this.swapLogger.error(invoiceData, "subscribeToInvoice(): Error calling htlcReceived(): ", e));
57
57
  this.activeSubscriptions.delete(hash);
58
58
  });
59
59
  this.swapLogger.debug(invoiceData, "subscribeToInvoice(): Subscribed to invoice payment");
@@ -79,7 +79,7 @@ class FromBtcLnTrusted extends SwapHandler_1.SwapHandler {
79
79
  //Result is either FromBtcLnTrustedSwapState.RECEIVED or FromBtcLnTrustedSwapState.CANCELED
80
80
  }
81
81
  catch (e) {
82
- console.error(e);
82
+ this.swapLogger.error(swap, "processPastSwap(): Error calling htlcReceived(): ", e);
83
83
  }
84
84
  return false;
85
85
  case "confirmed":
@@ -182,7 +182,7 @@ class FromBtcLnTrusted extends SwapHandler_1.SwapHandler {
182
182
  await invoiceData.setState(FromBtcLnTrustedSwap_1.FromBtcLnTrustedSwapState.SENT);
183
183
  await this.storageManager.saveData(invoice.id, null, invoiceData);
184
184
  }
185
- }).catch(e => console.error(e));
185
+ }).catch(e => this.swapLogger.error(invoiceData, "htlcReceived(): Error sending transfer txns", e));
186
186
  if (result == null) {
187
187
  //Cancel invoice
188
188
  await invoiceData.setState(FromBtcLnTrustedSwap_1.FromBtcLnTrustedSwapState.REFUNDED);
@@ -264,18 +264,16 @@ class FromBtcLnTrusted extends SwapHandler_1.SwapHandler {
264
264
  msg: "Invoice expired/canceled"
265
265
  };
266
266
  const arr = invoice.description.split("-");
267
- let chainIdentifier;
268
- let address;
269
- if (arr.length > 2 && arr[1] === "GAS") {
270
- chainIdentifier = arr[0];
271
- address = arr[2];
272
- }
273
- else {
274
- chainIdentifier = this.chains.default;
275
- address = invoice.description;
276
- }
267
+ if (arr.length < 3 || arr[1] !== "GAS")
268
+ throw {
269
+ _httpStatus: 200,
270
+ code: 10001,
271
+ msg: "Invoice expired/canceled"
272
+ };
273
+ const chainIdentifier = arr[0];
274
+ const address = arr[2];
277
275
  const { chainInterface } = this.getChain(chainIdentifier);
278
- if (!chainInterface.isValidAddress(address))
276
+ if (!chainInterface.isValidAddress(address, true))
279
277
  throw {
280
278
  _httpStatus: 200,
281
279
  code: 10001,
@@ -313,7 +311,7 @@ class FromBtcLnTrusted extends SwapHandler_1.SwapHandler {
313
311
  const createInvoice = (0, Utils_1.expressHandlerWrapper)(async (req, res) => {
314
312
  var _a;
315
313
  const metadata = { request: {}, times: {} };
316
- const chainIdentifier = req.query.chain ?? this.chains.default;
314
+ const chainIdentifier = req.query.chain;
317
315
  const { signer, chainInterface } = this.getChain(chainIdentifier);
318
316
  metadata.times.requestReceived = Date.now();
319
317
  /**
@@ -324,7 +322,7 @@ class FromBtcLnTrusted extends SwapHandler_1.SwapHandler {
324
322
  const parsedBody = (0, SchemaVerifier_1.verifySchema)(req.query, {
325
323
  address: (val) => val != null &&
326
324
  typeof (val) === "string" &&
327
- chainInterface.isValidAddress(val) ? val : null,
325
+ chainInterface.isValidAddress(val, true) ? val : null,
328
326
  token: (val) => val != null &&
329
327
  typeof (val) === "string" &&
330
328
  this.isTokenSupported(chainIdentifier, val) ? val : null,
@@ -385,7 +383,6 @@ class FromBtcLnTrusted extends SwapHandler_1.SwapHandler {
385
383
  abortController.signal.throwIfAborted();
386
384
  metadata.times.invoiceCreated = Date.now();
387
385
  metadata.invoiceResponse = { ...hodlInvoice };
388
- console.log("[From BTC-LN: REST.CreateInvoice] hodl invoice created: ", hodlInvoice);
389
386
  const createdSwap = new FromBtcLnTrustedSwap_1.FromBtcLnTrustedSwap(chainIdentifier, hodlInvoice.request, hodlInvoice.mtokens, swapFee, swapFeeInToken, totalInToken, secret.toString("hex"), parsedBody.address, useToken);
390
387
  metadata.times.swapCreated = Date.now();
391
388
  createdSwap.metadata = metadata;
@@ -1,5 +1,12 @@
1
1
  import { Request, Response } from "express";
2
2
  import { ServerParamEncoder } from "./paramcoders/server/ServerParamEncoder";
3
+ export type LoggerType = {
4
+ debug: (msg: string, ...args: any[]) => void;
5
+ info: (msg: string, ...args: any[]) => void;
6
+ warn: (msg: string, ...args: any[]) => void;
7
+ error: (msg: string, ...args: any[]) => void;
8
+ };
9
+ export declare function getLogger(prefix: string | (() => string)): LoggerType;
3
10
  export type DefinedRuntimeError = {
4
11
  code: number;
5
12
  msg?: string;
@@ -10,13 +17,6 @@ export declare function isDefinedRuntimeError(obj: any): obj is DefinedRuntimeEr
10
17
  export declare function expressHandlerWrapper(func: (req: Request, res: Response) => Promise<void>): ((req: Request, res: Response & {
11
18
  responseStream: ServerParamEncoder;
12
19
  }) => void);
13
- export type LoggerType = {
14
- debug: (msg: string, ...args: any[]) => void;
15
- info: (msg: string, ...args: any[]) => void;
16
- warn: (msg: string, ...args: any[]) => void;
17
- error: (msg: string, ...args: any[]) => void;
18
- };
19
- export declare function getLogger(prefix: string): LoggerType;
20
20
  export declare const HEX_REGEX: RegExp;
21
21
  export declare function serializeBN(bn: bigint | null): string | null;
22
22
  export declare function deserializeBN(str: string | null): bigint | null;
@@ -1,6 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAbortController = exports.bigIntSorter = exports.deserializeBN = exports.serializeBN = exports.HEX_REGEX = exports.getLogger = exports.expressHandlerWrapper = exports.isDefinedRuntimeError = void 0;
3
+ exports.getAbortController = exports.bigIntSorter = exports.deserializeBN = exports.serializeBN = exports.HEX_REGEX = exports.expressHandlerWrapper = exports.isDefinedRuntimeError = exports.getLogger = void 0;
4
+ function getLogger(prefix) {
5
+ return {
6
+ debug: (msg, ...args) => global.atomiqLogLevel >= 3 && console.debug((typeof (prefix) === "function" ? prefix() : prefix) + msg, ...args),
7
+ info: (msg, ...args) => global.atomiqLogLevel >= 2 && console.info((typeof (prefix) === "function" ? prefix() : prefix) + msg, ...args),
8
+ warn: (msg, ...args) => (global.atomiqLogLevel == null || global.atomiqLogLevel >= 1) && console.warn((typeof (prefix) === "function" ? prefix() : prefix) + msg, ...args),
9
+ error: (msg, ...args) => (global.atomiqLogLevel == null || global.atomiqLogLevel >= 0) && console.error((typeof (prefix) === "function" ? prefix() : prefix) + msg, ...args)
10
+ };
11
+ }
12
+ exports.getLogger = getLogger;
4
13
  function isDefinedRuntimeError(obj) {
5
14
  if (obj.code != null && typeof (obj.code) === "number") {
6
15
  if (obj.msg != null && typeof (obj.msg) !== "string")
@@ -12,6 +21,7 @@ function isDefinedRuntimeError(obj) {
12
21
  return false;
13
22
  }
14
23
  exports.isDefinedRuntimeError = isDefinedRuntimeError;
24
+ const expressHandlerWrapperLogger = getLogger("ExpressHandlerWrapper: ");
15
25
  function expressHandlerWrapper(func) {
16
26
  return (req, res) => {
17
27
  (async () => {
@@ -19,7 +29,7 @@ function expressHandlerWrapper(func) {
19
29
  await func(req, res);
20
30
  }
21
31
  catch (e) {
22
- console.error(e);
32
+ expressHandlerWrapperLogger.error("Error in called function " + req.path + ": ", e);
23
33
  let statusCode = 500;
24
34
  const obj = {
25
35
  code: 0,
@@ -46,15 +56,6 @@ function expressHandlerWrapper(func) {
46
56
  };
47
57
  }
48
58
  exports.expressHandlerWrapper = expressHandlerWrapper;
49
- function getLogger(prefix) {
50
- return {
51
- debug: (msg, ...args) => console.debug(prefix + msg, ...args),
52
- info: (msg, ...args) => console.info(prefix + msg, ...args),
53
- warn: (msg, ...args) => console.warn(prefix + msg, ...args),
54
- error: (msg, ...args) => console.error(prefix + msg, ...args)
55
- };
56
- }
57
- exports.getLogger = getLogger;
58
59
  exports.HEX_REGEX = /[0-9a-fA-F]+/;
59
60
  function serializeBN(bn) {
60
61
  return bn == null ? null : bn.toString(10);
@@ -4,6 +4,7 @@ exports.serverParamDecoder = exports.RequestParsingError = exports.RequestTimeou
4
4
  const SchemaVerifier_1 = require("../SchemaVerifier");
5
5
  const ParamDecoder_1 = require("../ParamDecoder");
6
6
  const ServerParamEncoder_1 = require("./ServerParamEncoder");
7
+ const Utils_1 = require("../../Utils");
7
8
  class RequestTimeoutError extends Error {
8
9
  constructor() {
9
10
  super("Request timed out");
@@ -20,6 +21,7 @@ class RequestParsingError extends Error {
20
21
  }
21
22
  }
22
23
  exports.RequestParsingError = RequestParsingError;
24
+ const logger = (0, Utils_1.getLogger)("ServerParamDecoder: ");
23
25
  const serverParamDecoder = (timeoutMillis) => (req, res, next) => {
24
26
  let timeout;
25
27
  res.responseStream = new ServerParamEncoder_1.ServerParamEncoder(res, 200, req);
@@ -43,14 +45,14 @@ const serverParamDecoder = (timeoutMillis) => (req, res, next) => {
43
45
  next();
44
46
  }
45
47
  catch (e) {
46
- console.error("ServerParamDecoder: error reading legacy (non-streaming) http request", e);
48
+ logger.error("error reading legacy (non-streaming) http request", e);
47
49
  req.destroy(new RequestParsingError());
48
50
  res.destroy(new RequestParsingError());
49
51
  }
50
52
  clearTimeout(timeout);
51
53
  });
52
54
  req.on("error", (e) => {
53
- console.error("ServerParamDecoder: error reading legacy (non-streaming) http request", e);
55
+ logger.error("error reading legacy (non-streaming) http request", e);
54
56
  });
55
57
  timeout = setTimeout(() => {
56
58
  req.destroy(new RequestTimeoutError());
@@ -64,7 +66,7 @@ const serverParamDecoder = (timeoutMillis) => (req, res, next) => {
64
66
  decoder.onData(data);
65
67
  }
66
68
  catch (e) {
67
- console.error("ServerParamDecoder: error reading streaming http request: on(\"data\")", e);
69
+ logger.error("error reading streaming http request: on(\"data\")", e);
68
70
  req.destroy(new RequestParsingError());
69
71
  res.destroy(new RequestParsingError());
70
72
  }
@@ -74,7 +76,7 @@ const serverParamDecoder = (timeoutMillis) => (req, res, next) => {
74
76
  decoder.onEnd();
75
77
  }
76
78
  catch (e) {
77
- console.error("ServerParamDecoder: error reading streaming http request: on(\"end\")", e);
79
+ logger.error("error reading streaming http request: on(\"end\")", e);
78
80
  req.destroy(new RequestParsingError());
79
81
  res.destroy(new RequestParsingError());
80
82
  }
@@ -85,7 +87,7 @@ const serverParamDecoder = (timeoutMillis) => (req, res, next) => {
85
87
  decoder.onError(e);
86
88
  }
87
89
  catch (e) {
88
- console.error("ServerParamDecoder: error reading streaming http request: on(\"error\")", e);
90
+ logger.error("error reading streaming http request: on(\"error\")", e);
89
91
  }
90
92
  });
91
93
  timeout = setTimeout(() => {
@@ -93,7 +95,7 @@ const serverParamDecoder = (timeoutMillis) => (req, res, next) => {
93
95
  decoder.onEnd();
94
96
  }
95
97
  catch (e) {
96
- console.error("ServerParamDecoder: error reading streaming http request: timeout", e);
98
+ logger.error("error reading streaming http request: timeout", e);
97
99
  }
98
100
  req.destroy(new RequestTimeoutError());
99
101
  res.destroy(new RequestTimeoutError());
@@ -64,4 +64,11 @@ export interface IBitcoinWallet {
64
64
  parsePsbt(psbt: Transaction): Promise<BtcTx>;
65
65
  getBlockheight(): Promise<number>;
66
66
  getFeeRate(): Promise<number>;
67
+ /**
68
+ * Post a task to be executed on the sequential thread of the wallet, this makes sure the UTXOs stay consistent during
69
+ * operation, it is recommended to use this approach when spending wallet UTXOs
70
+ *
71
+ * @param executor
72
+ */
73
+ execute(executor: () => Promise<void>): Promise<void>;
67
74
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/lp-lib",
3
- "version": "15.0.13",
3
+ "version": "16.0.0",
4
4
  "description": "Main functionality implementation for atomiq LP node",
5
5
  "main": "./dist/index.js",
6
6
  "types:": "./dist/index.d.ts",
@@ -22,11 +22,11 @@
22
22
  "author": "adambor",
23
23
  "license": "ISC",
24
24
  "dependencies": {
25
- "@atomiqlabs/base": "^11.0.0",
25
+ "@atomiqlabs/base": "^12.0.0",
26
26
  "@atomiqlabs/server-base": "^3.0.0",
27
27
  "@scure/btc-signer": "1.6.0",
28
28
  "express": "4.21.1",
29
- "promise-queue-ts": "0.0.1"
29
+ "promise-queue-ts": "1.0.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/express": "4.17.21",
package/src/index.ts CHANGED
@@ -13,6 +13,8 @@ export * from "./swaps/escrow/frombtc_abstract/FromBtcAbs";
13
13
  export * from "./swaps/escrow/frombtc_abstract/FromBtcSwapAbs";
14
14
  export * from "./swaps/escrow/frombtcln_abstract/FromBtcLnAbs";
15
15
  export * from "./swaps/escrow/frombtcln_abstract/FromBtcLnSwapAbs";
16
+ export * from "./swaps/escrow/frombtcln_autoinit/FromBtcLnAuto";
17
+ export * from "./swaps/escrow/frombtcln_autoinit/FromBtcLnAutoSwap";
16
18
  export * from "./swaps/escrow/tobtc_abstract/ToBtcAbs";
17
19
  export * from "./swaps/escrow/tobtc_abstract/ToBtcSwapAbs";
18
20
  export * from "./swaps/escrow/tobtcln_abstract/ToBtcLnAbs";
@@ -13,8 +13,6 @@ type InfoHandlerResponseEnvelope = {
13
13
 
14
14
  type InfoHandlerResponse = {
15
15
  envelope: string,
16
- address: string,
17
- signature: string,
18
16
  chains: {
19
17
  [chainIdentifier: string]: {
20
18
  address: string,
@@ -88,12 +86,8 @@ export class InfoHandler {
88
86
  };
89
87
  }
90
88
 
91
- const defaults = chains[this.chainData.default];
92
-
93
89
  const response: InfoHandlerResponse = {
94
90
  envelope,
95
- address: defaults.address,
96
- signature: defaults.signature,
97
91
  chains
98
92
  };
99
93
 
@@ -116,7 +116,7 @@ export interface IPlugin {
116
116
  onSwapRemove?(swap: SwapHandlerSwap): Promise<void>;
117
117
 
118
118
  onHandlePreFromBtcQuote?(
119
- swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
119
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV | SwapHandlerType.FROM_BTCLN_AUTO,
120
120
  request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
121
121
  requestedAmount: {input: boolean, amount: bigint, token: string},
122
122
  chainIdentifier: string,
@@ -125,7 +125,7 @@ export interface IPlugin {
125
125
  gasTokenAmount?: {input: false, amount: bigint, token: string}
126
126
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh>;
127
127
  onHandlePostFromBtcQuote?(
128
- swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
128
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV | SwapHandlerType.FROM_BTCLN_AUTO,
129
129
  request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
130
130
  requestedAmount: {input: boolean, amount: bigint, token: string, pricePrefetch?: Promise<bigint>},
131
131
  chainIdentifier: string,