@atomiqlabs/lp-lib 15.0.9 → 15.0.11

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,5 +1,5 @@
1
1
  import { BitcoinRpc } from "@atomiqlabs/base";
2
- import { FromBtcLnRequestType, FromBtcRequestType, FromBtcTrustedRequestType, ISwapPrice, MultichainData, RequestData, SpvVaultSwapRequestType, SwapHandler, SwapHandlerType, ToBtcLnRequestType, ToBtcRequestType } from "..";
2
+ import { FromBtcLnRequestType, FromBtcRequestType, FromBtcTrustedRequestType, ISwapPrice, MultichainData, RequestData, SpvVaultPostQuote, SpvVaultSwap, SpvVaultSwapRequestType, SwapHandler, SwapHandlerType, ToBtcLnRequestType, ToBtcRequestType } from "..";
3
3
  import { SwapHandlerSwap } from "../swaps/SwapHandlerSwap";
4
4
  import { Command } from "@atomiqlabs/server-base";
5
5
  import { FromBtcLnTrustedRequestType } from "../swaps/trusted/frombtcln_trusted/FromBtcLnTrusted";
@@ -128,6 +128,7 @@ export interface IPlugin {
128
128
  feePPM: bigint;
129
129
  networkFeeGetter: (amount: bigint) => Promise<bigint>;
130
130
  }): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh | ToBtcPluginQuote>;
131
+ onHandlePostedFromBtcQuote?(swapType: SwapHandlerType.FROM_BTC_SPV, request: RequestData<SpvVaultPostQuote>, swap: SpvVaultSwap): Promise<QuoteThrow | null>;
131
132
  onVaultSelection?(chainIdentifier: string, totalSats: bigint, requestedAmount: {
132
133
  amount: bigint;
133
134
  token: string;
@@ -1,6 +1,6 @@
1
1
  import { BitcoinRpc, SwapData } from "@atomiqlabs/base";
2
2
  import { IPlugin, PluginQuote, QuoteAmountTooHigh, QuoteAmountTooLow, QuoteSetFees, QuoteThrow, ToBtcPluginQuote } from "./IPlugin";
3
- import { FromBtcLnRequestType, FromBtcRequestType, FromBtcTrustedRequestType, ISwapPrice, MultichainData, RequestData, SpvVaultSwapRequestType, SwapHandler, SwapHandlerType, ToBtcLnRequestType, ToBtcRequestType } from "..";
3
+ import { FromBtcLnRequestType, FromBtcRequestType, FromBtcTrustedRequestType, ISwapPrice, MultichainData, RequestData, SpvVaultPostQuote, SpvVaultSwap, SpvVaultSwapRequestType, SwapHandler, SwapHandlerType, ToBtcLnRequestType, ToBtcRequestType } from "..";
4
4
  import { SwapHandlerSwap } from "../swaps/SwapHandlerSwap";
5
5
  import { FromBtcLnTrustedRequestType } from "../swaps/trusted/frombtcln_trusted/FromBtcLnTrusted";
6
6
  import { IBitcoinWallet } from "../wallets/IBitcoinWallet";
@@ -101,6 +101,7 @@ export declare class PluginManager {
101
101
  baseFeeInBtc: bigint;
102
102
  feePPM: bigint;
103
103
  }): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh>;
104
+ static onHandlePostedFromBtcQuote(swapType: SwapHandlerType.FROM_BTC_SPV, request: RequestData<SpvVaultPostQuote>, swap: SpvVaultSwap): Promise<QuoteThrow | null>;
104
105
  static onVaultSelection(chainIdentifier: string, totalSats: bigint, requestedAmount: {
105
106
  amount: bigint;
106
107
  token: string;
@@ -214,6 +214,21 @@ class PluginManager {
214
214
  }
215
215
  return null;
216
216
  }
217
+ static async onHandlePostedFromBtcQuote(swapType, request, swap) {
218
+ for (let plugin of PluginManager.plugins.values()) {
219
+ try {
220
+ if (plugin.onHandlePostedFromBtcQuote != null) {
221
+ const result = await plugin.onHandlePostedFromBtcQuote(swapType, request, swap);
222
+ if (result != null && (0, IPlugin_1.isQuoteThrow)(result))
223
+ return result;
224
+ }
225
+ }
226
+ catch (e) {
227
+ pluginLogger.error(plugin, "onHandlePostedFromBtcQuote(): plugin error", e);
228
+ }
229
+ }
230
+ return null;
231
+ }
217
232
  static async onVaultSelection(chainIdentifier, totalSats, requestedAmount, gasAmount) {
218
233
  for (let plugin of PluginManager.plugins.values()) {
219
234
  try {
@@ -309,7 +309,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
309
309
  if (swap.sending)
310
310
  return;
311
311
  //Bitcoin transaction was signed (maybe also sent)
312
- const tx = await (0, BitcoinUtils_1.checkTransactionReplaced)(swap.txId, swap.btcRawTx, this.bitcoin);
312
+ const tx = await (0, BitcoinUtils_1.checkTransactionReplaced)(swap.txId, swap.btcRawTx, this.bitcoinRpc);
313
313
  const isTxSent = tx != null;
314
314
  if (!isTxSent) {
315
315
  //Reset the state to COMMITED
@@ -13,6 +13,7 @@ const crypto_1 = require("crypto");
13
13
  const btc_signer_1 = require("@scure/btc-signer");
14
14
  const SpvVaults_1 = require("./SpvVaults");
15
15
  const BitcoinUtils_1 = require("../../utils/BitcoinUtils");
16
+ const AmountAssertions_1 = require("../assertions/AmountAssertions");
16
17
  const TX_MAX_VSIZE = 16 * 1024;
17
18
  class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
18
19
  constructor(storageDirectory, vaultStorage, path, chainsData, swapPricing, bitcoin, bitcoinRpc, spvVaultSigner, config) {
@@ -105,7 +106,7 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
105
106
  const foundWithdrawal = vault.pendingWithdrawals.find(val => val.btcTx.txid === swap.btcTxId);
106
107
  let tx = foundWithdrawal?.btcTx;
107
108
  if (tx == null)
108
- tx = await this.bitcoin.getWalletTransaction(swap.btcTxId);
109
+ tx = await this.bitcoinRpc.getTransaction(swap.btcTxId);
109
110
  if (tx == null) {
110
111
  await this.removeSwapData(swap, SpvVaultSwap_1.SpvVaultSwapState.FAILED);
111
112
  return;
@@ -128,7 +129,7 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
128
129
  const foundWithdrawal = vault.pendingWithdrawals.find(val => val.btcTx.txid === swap.btcTxId);
129
130
  let tx = foundWithdrawal?.btcTx;
130
131
  if (tx == null)
131
- tx = await this.bitcoin.getWalletTransaction(swap.btcTxId);
132
+ tx = await this.bitcoinRpc.getTransaction(swap.btcTxId);
132
133
  if (tx == null) {
133
134
  await this.removeSwapData(swap, SpvVaultSwap_1.SpvVaultSwapState.DOUBLE_SPENT);
134
135
  return;
@@ -343,6 +344,8 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
343
344
  msg: "Used vault not found!"
344
345
  };
345
346
  }
347
+ //Check the posted quote with the plugins
348
+ AmountAssertions_1.AmountAssertions.handlePluginErrorResponses(await PluginManager_1.PluginManager.onHandlePostedFromBtcQuote(this.type, { chainIdentifier: swap.chainIdentifier, raw: req, parsed: parsedBody, metadata }, swap));
346
349
  //Try parse psbt
347
350
  let transaction;
348
351
  try {
@@ -330,7 +330,7 @@ class SpvVaults {
330
330
  if (pendingWithdrawal.sending)
331
331
  continue;
332
332
  //Check all the pending withdrawals that were not finalized yet
333
- const btcTx = await (0, BitcoinUtils_1.checkTransactionReplacedRpc)(pendingWithdrawal.btcTx.txid, pendingWithdrawal.btcTx.raw, this.bitcoinRpc);
333
+ const btcTx = await (0, BitcoinUtils_1.checkTransactionReplaced)(pendingWithdrawal.btcTx.txid, pendingWithdrawal.btcTx.raw, this.bitcoinRpc);
334
334
  if (btcTx == null) {
335
335
  //Probable double-spend, remove from pending withdrawals
336
336
  if (!vault.doubleSpendPendingWithdrawal(pendingWithdrawal)) {
@@ -608,7 +608,7 @@ class FromBtcTrusted extends SwapHandler_1.SwapHandler {
608
608
  }
609
609
  async checkDoubleSpends() {
610
610
  for (let swap of this.doubleSpendWatchdogSwaps.keys()) {
611
- const tx = await this.bitcoin.getWalletTransaction(swap.txId);
611
+ const tx = await this.bitcoinRpc.getTransaction(swap.txId);
612
612
  if (tx == null) {
613
613
  this.swapLogger.debug(swap, "checkDoubleSpends(): Swap was double spent, burning... - original txId: " + swap.txId);
614
614
  this.processPastSwap(swap, null, null);
@@ -1,6 +1,4 @@
1
1
  import { TransactionInput } from "@scure/btc-signer/psbt";
2
2
  import { BitcoinRpc, BtcTx } from "@atomiqlabs/base";
3
- import { IBitcoinWallet } from "../wallets/IBitcoinWallet";
4
3
  export declare function isLegacyInput(input: TransactionInput): boolean;
5
- export declare function checkTransactionReplaced(txId: string, txRaw: string, bitcoin: IBitcoinWallet): Promise<BtcTx>;
6
- export declare function checkTransactionReplacedRpc(txId: string, txRaw: string, bitcoin: BitcoinRpc<any>): Promise<BtcTx>;
4
+ export declare function checkTransactionReplaced(txId: string, txRaw: string, bitcoin: BitcoinRpc<any>): Promise<BtcTx>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.checkTransactionReplacedRpc = exports.checkTransactionReplaced = exports.isLegacyInput = void 0;
3
+ exports.checkTransactionReplaced = exports.isLegacyInput = void 0;
4
4
  const utxo_1 = require("@scure/btc-signer/utxo");
5
5
  const btc_signer_1 = require("@scure/btc-signer");
6
6
  const Utils_1 = require("./Utils");
@@ -46,20 +46,6 @@ function isLegacyInput(input) {
46
46
  }
47
47
  exports.isLegacyInput = isLegacyInput;
48
48
  async function checkTransactionReplaced(txId, txRaw, bitcoin) {
49
- const existingTx = await bitcoin.getWalletTransaction(txId);
50
- if (existingTx != null)
51
- return existingTx;
52
- //Try to re-broadcast
53
- try {
54
- await bitcoin.sendRawTransaction(txRaw);
55
- }
56
- catch (e) {
57
- logger.error("checkTransactionReplaced(" + txId + "): Error when trying to re-broadcast raw transaction: ", e);
58
- }
59
- return await bitcoin.getWalletTransaction(txId);
60
- }
61
- exports.checkTransactionReplaced = checkTransactionReplaced;
62
- async function checkTransactionReplacedRpc(txId, txRaw, bitcoin) {
63
49
  const existingTx = await bitcoin.getTransaction(txId);
64
50
  if (existingTx != null)
65
51
  return existingTx;
@@ -72,4 +58,4 @@ async function checkTransactionReplacedRpc(txId, txRaw, bitcoin) {
72
58
  }
73
59
  return await bitcoin.getTransaction(txId);
74
60
  }
75
- exports.checkTransactionReplacedRpc = checkTransactionReplacedRpc;
61
+ exports.checkTransactionReplaced = checkTransactionReplaced;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/lp-lib",
3
- "version": "15.0.9",
3
+ "version": "15.0.11",
4
4
  "description": "Main functionality implementation for atomiq LP node",
5
5
  "main": "./dist/index.js",
6
6
  "types:": "./dist/index.d.ts",
@@ -1,8 +1,8 @@
1
- import {BitcoinRpc, SpvWithdrawalTransactionData, SwapData} from "@atomiqlabs/base";
1
+ import {BitcoinRpc} from "@atomiqlabs/base";
2
2
  import {
3
3
  FromBtcLnRequestType,
4
4
  FromBtcRequestType, FromBtcTrustedRequestType,
5
- ISwapPrice, MultichainData, RequestData, SpvVaultSwapRequestType,
5
+ ISwapPrice, MultichainData, RequestData, SpvVaultPostQuote, SpvVaultSwap, SpvVaultSwapRequestType,
6
6
  SwapHandler, SwapHandlerType,
7
7
  ToBtcLnRequestType,
8
8
  ToBtcRequestType
@@ -151,6 +151,12 @@ export interface IPlugin {
151
151
  fees: {baseFeeInBtc: bigint, feePPM: bigint, networkFeeGetter: (amount: bigint) => Promise<bigint>}
152
152
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh | ToBtcPluginQuote>;
153
153
 
154
+ onHandlePostedFromBtcQuote?(
155
+ swapType: SwapHandlerType.FROM_BTC_SPV,
156
+ request: RequestData<SpvVaultPostQuote>,
157
+ swap: SpvVaultSwap
158
+ ): Promise<QuoteThrow | null>;
159
+
154
160
  onVaultSelection?(
155
161
  chainIdentifier: string,
156
162
  totalSats: bigint,
@@ -1,4 +1,4 @@
1
- import {BitcoinRpc, SpvWithdrawalTransactionData, SwapData} from "@atomiqlabs/base";
1
+ import {BitcoinRpc, SwapData} from "@atomiqlabs/base";
2
2
  import {
3
3
  IPlugin, isPluginQuote, isQuoteAmountTooHigh, isQuoteAmountTooLow, isQuoteSetFees,
4
4
  isQuoteThrow, isToBtcPluginQuote, PluginQuote,
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  FromBtcLnRequestType,
12
12
  FromBtcRequestType, FromBtcTrustedRequestType,
13
- ISwapPrice, MultichainData, RequestData, SpvVaultSwapRequestType,
13
+ ISwapPrice, MultichainData, RequestData, SpvVaultPostQuote, SpvVaultSwap, SpvVaultSwapRequestType,
14
14
  SwapHandler, SwapHandlerType,
15
15
  ToBtcLnRequestType,
16
16
  ToBtcRequestType
@@ -291,6 +291,24 @@ export class PluginManager {
291
291
  return null;
292
292
  }
293
293
 
294
+ static async onHandlePostedFromBtcQuote(
295
+ swapType: SwapHandlerType.FROM_BTC_SPV,
296
+ request: RequestData<SpvVaultPostQuote>,
297
+ swap: SpvVaultSwap
298
+ ): Promise<QuoteThrow | null> {
299
+ for(let plugin of PluginManager.plugins.values()) {
300
+ try {
301
+ if(plugin.onHandlePostedFromBtcQuote!=null) {
302
+ const result = await plugin.onHandlePostedFromBtcQuote(swapType, request, swap);
303
+ if(result!=null && isQuoteThrow(result)) return result;
304
+ }
305
+ } catch (e) {
306
+ pluginLogger.error(plugin, "onHandlePostedFromBtcQuote(): plugin error", e);
307
+ }
308
+ }
309
+ return null;
310
+ }
311
+
294
312
  static async onVaultSelection(
295
313
  chainIdentifier: string,
296
314
  totalSats: bigint,
@@ -396,7 +396,7 @@ export class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState>
396
396
  if(swap.state===ToBtcSwapState.BTC_SENDING) {
397
397
  if(swap.sending) return;
398
398
  //Bitcoin transaction was signed (maybe also sent)
399
- const tx = await checkTransactionReplaced(swap.txId, swap.btcRawTx, this.bitcoin);
399
+ const tx = await checkTransactionReplaced(swap.txId, swap.btcRawTx, this.bitcoinRpc);
400
400
 
401
401
  const isTxSent = tx!=null;
402
402
  if(!isTxSent) {
@@ -27,9 +27,10 @@ import {ServerParamEncoder} from "../../utils/paramcoders/server/ServerParamEnco
27
27
  import {FieldTypeEnum} from "../../utils/paramcoders/SchemaVerifier";
28
28
  import {FromBtcAmountAssertions} from "../assertions/FromBtcAmountAssertions";
29
29
  import {randomBytes} from "crypto";
30
- import {getInputType, OutScript, Transaction} from "@scure/btc-signer";
30
+ import {Transaction} from "@scure/btc-signer";
31
31
  import {SpvVaults, VAULT_DUST_AMOUNT} from "./SpvVaults";
32
- import {checkTransactionReplaced, isLegacyInput} from "../../utils/BitcoinUtils";
32
+ import {isLegacyInput} from "../../utils/BitcoinUtils";
33
+ import {AmountAssertions} from "../assertions/AmountAssertions";
33
34
 
34
35
  export type SpvVaultSwapHandlerConfig = SwapBaseConfig & {
35
36
  vaultsCheckInterval: number,
@@ -170,7 +171,7 @@ export class SpvVaultSwapHandler extends SwapHandler<SpvVaultSwap, SpvVaultSwapS
170
171
  const vault = await this.Vaults.getVault(swap.chainIdentifier, swap.vaultOwner, swap.vaultId);
171
172
  const foundWithdrawal = vault.pendingWithdrawals.find(val => val.btcTx.txid === swap.btcTxId);
172
173
  let tx = foundWithdrawal?.btcTx;
173
- if(tx==null) tx = await this.bitcoin.getWalletTransaction(swap.btcTxId);
174
+ if(tx==null) tx = await this.bitcoinRpc.getTransaction(swap.btcTxId);
174
175
 
175
176
  if(tx==null) {
176
177
  await this.removeSwapData(swap, SpvVaultSwapState.FAILED);
@@ -191,7 +192,7 @@ export class SpvVaultSwapHandler extends SwapHandler<SpvVaultSwap, SpvVaultSwapS
191
192
  const vault = await this.Vaults.getVault(swap.chainIdentifier, swap.vaultOwner, swap.vaultId);
192
193
  const foundWithdrawal = vault.pendingWithdrawals.find(val => val.btcTx.txid === swap.btcTxId);
193
194
  let tx = foundWithdrawal?.btcTx;
194
- if(tx==null) tx = await this.bitcoin.getWalletTransaction(swap.btcTxId);
195
+ if(tx==null) tx = await this.bitcoinRpc.getTransaction(swap.btcTxId);
195
196
 
196
197
  if(tx==null) {
197
198
  await this.removeSwapData(swap, SpvVaultSwapState.DOUBLE_SPENT);
@@ -470,6 +471,13 @@ export class SpvVaultSwapHandler extends SwapHandler<SpvVaultSwap, SpvVaultSwapS
470
471
  };
471
472
  }
472
473
 
474
+ //Check the posted quote with the plugins
475
+ AmountAssertions.handlePluginErrorResponses(await PluginManager.onHandlePostedFromBtcQuote(
476
+ this.type,
477
+ {chainIdentifier: swap.chainIdentifier, raw: req, parsed: parsedBody, metadata},
478
+ swap
479
+ ));
480
+
473
481
  //Try parse psbt
474
482
  let transaction: Transaction;
475
483
  try {
@@ -15,7 +15,7 @@ import {ISpvVaultSigner} from "../../wallets/ISpvVaultSigner";
15
15
  import {AmountAssertions} from "../assertions/AmountAssertions";
16
16
  import {ChainData} from "../SwapHandler";
17
17
  import {Transaction} from "@scure/btc-signer";
18
- import {checkTransactionReplacedRpc} from "../../utils/BitcoinUtils";
18
+ import {checkTransactionReplaced} from "../../utils/BitcoinUtils";
19
19
 
20
20
  export const VAULT_DUST_AMOUNT = 600;
21
21
  const VAULT_INIT_CONFIRMATIONS = 2;
@@ -389,7 +389,7 @@ export class SpvVaults {
389
389
  if(pendingWithdrawal.sending) continue;
390
390
 
391
391
  //Check all the pending withdrawals that were not finalized yet
392
- const btcTx = await checkTransactionReplacedRpc(pendingWithdrawal.btcTx.txid, pendingWithdrawal.btcTx.raw, this.bitcoinRpc);
392
+ const btcTx = await checkTransactionReplaced(pendingWithdrawal.btcTx.txid, pendingWithdrawal.btcTx.raw, this.bitcoinRpc);
393
393
  if(btcTx==null) {
394
394
  //Probable double-spend, remove from pending withdrawals
395
395
  if(!vault.doubleSpendPendingWithdrawal(pendingWithdrawal)) {
@@ -702,7 +702,7 @@ export class FromBtcTrusted extends SwapHandler<FromBtcTrustedSwap, FromBtcTrust
702
702
 
703
703
  private async checkDoubleSpends(): Promise<void> {
704
704
  for(let swap of this.doubleSpendWatchdogSwaps.keys()) {
705
- const tx = await this.bitcoin.getWalletTransaction(swap.txId);
705
+ const tx = await this.bitcoinRpc.getTransaction(swap.txId);
706
706
  if(tx==null) {
707
707
  this.swapLogger.debug(swap, "checkDoubleSpends(): Swap was double spent, burning... - original txId: "+swap.txId);
708
708
  this.processPastSwap(swap, null, null);
@@ -46,19 +46,7 @@ export function isLegacyInput(input: TransactionInput): boolean {
46
46
  return true;
47
47
  }
48
48
 
49
- export async function checkTransactionReplaced(txId: string, txRaw: string, bitcoin: IBitcoinWallet): Promise<BtcTx> {
50
- const existingTx = await bitcoin.getWalletTransaction(txId);
51
- if(existingTx!=null) return existingTx;
52
- //Try to re-broadcast
53
- try {
54
- await bitcoin.sendRawTransaction(txRaw);
55
- } catch (e) {
56
- logger.error("checkTransactionReplaced("+txId+"): Error when trying to re-broadcast raw transaction: ", e);
57
- }
58
- return await bitcoin.getWalletTransaction(txId);
59
- }
60
-
61
- export async function checkTransactionReplacedRpc(txId: string, txRaw: string, bitcoin: BitcoinRpc<any>): Promise<BtcTx> {
49
+ export async function checkTransactionReplaced(txId: string, txRaw: string, bitcoin: BitcoinRpc<any>): Promise<BtcTx> {
62
50
  const existingTx = await bitcoin.getTransaction(txId);
63
51
  if(existingTx!=null) return existingTx;
64
52
  //Try to re-broadcast