@atomiqlabs/lp-lib 10.3.11 → 11.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 (94) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +2 -4
  3. package/dist/plugins/IPlugin.d.ts +3 -2
  4. package/dist/plugins/PluginManager.d.ts +3 -2
  5. package/dist/plugins/PluginManager.js +2 -2
  6. package/dist/swaps/FromBtcBaseSwap.d.ts +5 -1
  7. package/dist/swaps/FromBtcBaseSwap.js +20 -0
  8. package/dist/swaps/FromBtcBaseSwapHandler.d.ts +1 -0
  9. package/dist/swaps/FromBtcBaseSwapHandler.js +1 -1
  10. package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +8 -6
  11. package/dist/swaps/FromBtcLnBaseSwapHandler.js +7 -5
  12. package/dist/swaps/SwapHandler.d.ts +1 -4
  13. package/dist/swaps/SwapHandler.js +1 -2
  14. package/dist/swaps/SwapHandlerSwap.d.ts +4 -0
  15. package/dist/swaps/SwapHandlerSwap.js +9 -1
  16. package/dist/swaps/ToBtcBaseSwap.d.ts +3 -1
  17. package/dist/swaps/ToBtcBaseSwap.js +8 -2
  18. package/dist/swaps/ToBtcBaseSwapHandler.d.ts +1 -0
  19. package/dist/swaps/ToBtcBaseSwapHandler.js +1 -1
  20. package/dist/swaps/frombtc_abstract/FromBtcAbs.d.ts +3 -5
  21. package/dist/swaps/frombtc_abstract/FromBtcAbs.js +18 -25
  22. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.d.ts +1 -4
  23. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.js +3 -16
  24. package/dist/swaps/frombtc_trusted/FromBtcTrusted.d.ts +6 -9
  25. package/dist/swaps/frombtc_trusted/FromBtcTrusted.js +238 -137
  26. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.d.ts +9 -6
  27. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.js +15 -10
  28. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.d.ts +2 -2
  29. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.js +42 -62
  30. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +1 -6
  31. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.js +2 -14
  32. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.d.ts +3 -5
  33. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.js +64 -80
  34. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.d.ts +1 -2
  35. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.js +5 -8
  36. package/dist/swaps/tobtc_abstract/ToBtcAbs.d.ts +5 -125
  37. package/dist/swaps/tobtc_abstract/ToBtcAbs.js +41 -334
  38. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.d.ts +1 -4
  39. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.js +2 -11
  40. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.d.ts +5 -55
  41. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.js +152 -398
  42. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.d.ts +1 -6
  43. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.js +2 -15
  44. package/dist/utils/Utils.d.ts +0 -10
  45. package/dist/utils/Utils.js +1 -34
  46. package/dist/wallets/IBitcoinWallet.d.ts +62 -0
  47. package/dist/wallets/IBitcoinWallet.js +2 -0
  48. package/dist/wallets/ILightningWallet.d.ts +118 -0
  49. package/dist/wallets/ILightningWallet.js +37 -0
  50. package/package.json +4 -9
  51. package/src/index.ts +3 -5
  52. package/src/plugins/IPlugin.ts +4 -2
  53. package/src/plugins/PluginManager.ts +6 -3
  54. package/src/swaps/FromBtcBaseSwap.ts +24 -1
  55. package/src/swaps/FromBtcBaseSwapHandler.ts +6 -2
  56. package/src/swaps/FromBtcLnBaseSwapHandler.ts +22 -6
  57. package/src/swaps/SwapHandler.ts +1 -8
  58. package/src/swaps/SwapHandlerSwap.ts +14 -1
  59. package/src/swaps/ToBtcBaseSwap.ts +12 -3
  60. package/src/swaps/ToBtcBaseSwapHandler.ts +6 -2
  61. package/src/swaps/frombtc_abstract/FromBtcAbs.ts +24 -28
  62. package/src/swaps/frombtc_abstract/FromBtcSwapAbs.ts +3 -18
  63. package/src/swaps/frombtc_trusted/FromBtcTrusted.ts +260 -159
  64. package/src/swaps/frombtc_trusted/FromBtcTrustedSwap.ts +22 -15
  65. package/src/swaps/frombtcln_abstract/FromBtcLnAbs.ts +69 -79
  66. package/src/swaps/frombtcln_abstract/FromBtcLnSwapAbs.ts +3 -20
  67. package/src/swaps/frombtcln_trusted/FromBtcLnTrusted.ts +80 -97
  68. package/src/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.ts +6 -9
  69. package/src/swaps/tobtc_abstract/ToBtcAbs.ts +52 -410
  70. package/src/swaps/tobtc_abstract/ToBtcSwapAbs.ts +3 -18
  71. package/src/swaps/tobtcln_abstract/ToBtcLnAbs.ts +157 -434
  72. package/src/swaps/tobtcln_abstract/ToBtcLnSwapAbs.ts +3 -20
  73. package/src/utils/Utils.ts +0 -31
  74. package/src/wallets/IBitcoinWallet.ts +66 -0
  75. package/src/wallets/ILightningWallet.ts +179 -0
  76. package/dist/fees/OneDollarFeeEstimator.d.ts +0 -16
  77. package/dist/fees/OneDollarFeeEstimator.js +0 -71
  78. package/dist/utils/coinselect2/accumulative.d.ts +0 -6
  79. package/dist/utils/coinselect2/accumulative.js +0 -44
  80. package/dist/utils/coinselect2/blackjack.d.ts +0 -6
  81. package/dist/utils/coinselect2/blackjack.js +0 -41
  82. package/dist/utils/coinselect2/index.d.ts +0 -16
  83. package/dist/utils/coinselect2/index.js +0 -40
  84. package/dist/utils/coinselect2/utils.d.ts +0 -64
  85. package/dist/utils/coinselect2/utils.js +0 -121
  86. package/src/fees/OneDollarFeeEstimator.ts +0 -95
  87. package/src/utils/coinselect2/accumulative.js +0 -32
  88. package/src/utils/coinselect2/accumulative.ts +0 -58
  89. package/src/utils/coinselect2/blackjack.js +0 -29
  90. package/src/utils/coinselect2/blackjack.ts +0 -54
  91. package/src/utils/coinselect2/index.js +0 -16
  92. package/src/utils/coinselect2/index.ts +0 -50
  93. package/src/utils/coinselect2/utils.js +0 -110
  94. package/src/utils/coinselect2/utils.ts +0 -183
@@ -11,15 +11,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ToBtcAbs = void 0;
13
13
  const BN = require("bn.js");
14
- const bitcoin = require("bitcoinjs-lib");
15
- const lncli = require("ln-service");
16
14
  const ToBtcSwapAbs_1 = require("./ToBtcSwapAbs");
17
15
  const SwapHandler_1 = require("../SwapHandler");
18
16
  const base_1 = require("@atomiqlabs/base");
19
17
  const Utils_1 = require("../../utils/Utils");
20
18
  const PluginManager_1 = require("../../plugins/PluginManager");
21
- const coinselect2_1 = require("../../utils/coinselect2");
22
- const utils_1 = require("../../utils/coinselect2/utils");
23
19
  const crypto_1 = require("crypto");
24
20
  const SchemaVerifier_1 = require("../../utils/paramcoders/SchemaVerifier");
25
21
  const ServerParamDecoder_1 = require("../../utils/paramcoders/server/ServerParamDecoder");
@@ -30,23 +26,14 @@ const OUTPUT_SCRIPT_MAX_LENGTH = 200;
30
26
  * Handler for to BTC swaps, utilizing PTLCs (proof-time locked contracts) using btc relay (on-chain bitcoin SPV)
31
27
  */
32
28
  class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
33
- constructor(storageDirectory, path, chainData, lnd, swapPricing, bitcoinRpc, config) {
34
- super(storageDirectory, path, chainData, lnd, swapPricing);
35
- this.CONFIRMATIONS_REQUIRED = 1;
36
- this.ADDRESS_FORMAT_MAP = {
37
- "p2wpkh": "p2wpkh",
38
- "np2wpkh": "p2sh-p2wpkh",
39
- "p2tr": "p2tr"
40
- };
41
- this.LND_CHANGE_OUTPUT_TYPE = "p2tr";
42
- this.UTXO_CACHE_TIMEOUT = 5 * 1000;
43
- this.CHANNEL_COUNT_CACHE_TIMEOUT = 30 * 1000;
29
+ constructor(storageDirectory, path, chainData, bitcoin, swapPricing, bitcoinRpc, config) {
30
+ super(storageDirectory, path, chainData, swapPricing);
44
31
  this.type = SwapHandler_1.SwapHandlerType.TO_BTC;
45
32
  this.activeSubscriptions = {};
46
33
  this.sendBtcQueue = new promise_queue_ts_1.PromiseQueue();
47
34
  this.bitcoinRpc = bitcoinRpc;
35
+ this.bitcoin = bitcoin;
48
36
  this.config = config;
49
- this.config.onchainReservedPerChannel = this.config.onchainReservedPerChannel || 40000;
50
37
  }
51
38
  /**
52
39
  * Returns the payment hash of the swap, takes swap nonce into account. Payment hash is chain-specific.
@@ -55,189 +42,17 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
55
42
  * @param address
56
43
  * @param nonce
57
44
  * @param amount
58
- * @param bitcoinNetwork
59
45
  */
60
- getHash(chainIdentifier, address, nonce, amount, bitcoinNetwork) {
61
- const parsedOutputScript = bitcoin.address.toOutputScript(address, bitcoinNetwork);
46
+ getHash(chainIdentifier, address, nonce, amount) {
47
+ const parsedOutputScript = this.bitcoin.toOutputScript(address);
62
48
  const { swapContract } = this.getChain(chainIdentifier);
63
49
  return swapContract.getHashForOnchain(parsedOutputScript, amount, nonce);
64
50
  }
65
- /**
66
- * Returns spendable UTXOs, these are either confirmed UTXOs, or unconfirmed ones that are either whitelisted,
67
- * or created by our transactions (and therefore only we could doublespend)
68
- *
69
- * @private
70
- */
71
- getSpendableUtxos() {
72
- return __awaiter(this, void 0, void 0, function* () {
73
- const resBlockheight = yield lncli.getHeight({
74
- lnd: this.LND
75
- });
76
- const blockheight = resBlockheight.current_block_height;
77
- const resChainTxns = yield lncli.getChainTransactions({
78
- lnd: this.LND,
79
- after: blockheight - this.CONFIRMATIONS_REQUIRED
80
- });
81
- const selfUTXOs = PluginManager_1.PluginManager.getWhitelistedTxIds();
82
- const transactions = resChainTxns.transactions;
83
- for (let tx of transactions) {
84
- if (tx.is_outgoing) {
85
- selfUTXOs.add(tx.id);
86
- }
87
- }
88
- const resUtxos = yield lncli.getUtxos({
89
- lnd: this.LND
90
- });
91
- return resUtxos.utxos.filter(utxo => utxo.confirmation_count >= this.CONFIRMATIONS_REQUIRED || selfUTXOs.has(utxo.transaction_id));
92
- });
93
- }
94
- /**
95
- * Returns utxo pool to be used by the coinselection algorithm
96
- *
97
- * @private
98
- */
99
- getUtxoPool(useCached = false) {
100
- return __awaiter(this, void 0, void 0, function* () {
101
- if (!useCached || this.cachedUtxos == null || this.cachedUtxos.timestamp < Date.now() - this.UTXO_CACHE_TIMEOUT) {
102
- const utxos = yield this.getSpendableUtxos();
103
- let totalSpendable = 0;
104
- const utxoPool = utxos.map(utxo => {
105
- totalSpendable += utxo.tokens;
106
- return {
107
- vout: utxo.transaction_vout,
108
- txId: utxo.transaction_id,
109
- value: utxo.tokens,
110
- type: this.ADDRESS_FORMAT_MAP[utxo.address_format],
111
- outputScript: Buffer.from(utxo.output_script, "hex"),
112
- address: utxo.address,
113
- confirmations: utxo.confirmation_count
114
- };
115
- });
116
- this.cachedUtxos = {
117
- utxos: utxoPool,
118
- timestamp: Date.now()
119
- };
120
- this.logger.info("getUtxoPool(): total spendable value: " + totalSpendable + " num utxos: " + utxoPool.length);
121
- }
122
- return this.cachedUtxos.utxos;
123
- });
124
- }
125
- /**
126
- * Checks whether a coinselect result leaves enough funds to cover potential lightning anchor transaction fees
127
- *
128
- * @param utxoPool
129
- * @param obj
130
- * @param satsPerVbyte
131
- * @param useCached Whether to use a cached channel count
132
- * @param initialOutputLength
133
- * @private
134
- * @returns true if alright, false if the coinselection doesn't leave enough funds for anchor fees
135
- */
136
- isLeavingEnoughForLightningAnchors(utxoPool, obj, satsPerVbyte, useCached = false, initialOutputLength = 1) {
137
- return __awaiter(this, void 0, void 0, function* () {
138
- if (obj.inputs == null || obj.outputs == null)
139
- return false;
140
- const spentInputs = new Set();
141
- obj.inputs.forEach(txIn => {
142
- spentInputs.add(txIn.txId + ":" + txIn.vout);
143
- });
144
- let leavesValue = new BN(0);
145
- utxoPool.forEach(val => {
146
- const utxoEconomicalValue = new BN(val.value).sub(satsPerVbyte.mul(new BN(utils_1.utils.inputBytes(val).length)));
147
- if (
148
- //Utxo not spent
149
- !spentInputs.has(val.txId + ":" + val.vout) &&
150
- //Only economical utxos at current fees
151
- !utxoEconomicalValue.isNeg()) {
152
- leavesValue = leavesValue.add(utxoEconomicalValue);
153
- }
154
- });
155
- if (obj.outputs.length > initialOutputLength) {
156
- const changeUtxo = obj.outputs[obj.outputs.length - 1];
157
- leavesValue = leavesValue.add(new BN(changeUtxo.value).sub(satsPerVbyte.mul(new BN(utils_1.utils.inputBytes(changeUtxo).length))));
158
- }
159
- if (!useCached || this.cachedChannelCount == null || this.cachedChannelCount.timestamp < Date.now() - this.CHANNEL_COUNT_CACHE_TIMEOUT) {
160
- const { channels } = yield lncli.getChannels({ lnd: this.LND });
161
- this.cachedChannelCount = {
162
- count: channels.length,
163
- timestamp: Date.now()
164
- };
165
- }
166
- return leavesValue.gt(new BN(this.config.onchainReservedPerChannel).mul(new BN(this.cachedChannelCount.count)));
167
- });
168
- }
169
- /**
170
- * Gets the change address from the underlying LND instance
171
- *
172
- * @private
173
- */
174
- getChangeAddress() {
175
- return new Promise((resolve, reject) => {
176
- this.LND.wallet.nextAddr({
177
- type: 4,
178
- change: true
179
- }, (err, res) => {
180
- if (err != null) {
181
- reject([503, 'UnexpectedErrGettingNextAddr', { err }]);
182
- return;
183
- }
184
- resolve(res.addr);
185
- });
186
- });
187
- }
188
- /**
189
- * Computes bitcoin on-chain network fee, takes channel reserve & network fee multiplier into consideration
190
- *
191
- * @param targetAddress Bitcoin address to send the funds to
192
- * @param targetAmount Amount of funds to send to the address
193
- * @param estimate Whether the chain fee should be just estimated and therefore cached utxo set could be used
194
- * @param multiplierPPM Multiplier for the sats/vB returned from the fee estimator in PPM (parts per million)
195
- * @private
196
- * @returns Fee estimate & inputs/outputs to use when constructing transaction, or null in case of not enough funds
197
- */
198
- getChainFee(targetAddress, targetAmount, estimate = false, multiplierPPM) {
199
- return __awaiter(this, void 0, void 0, function* () {
200
- let feeRate = this.config.feeEstimator == null
201
- ? yield lncli.getChainFeeRate({ lnd: this.LND })
202
- .then(res => res.tokens_per_vbyte)
203
- .catch(e => this.logger.error("getChainFee(): LND getChainFeeRate error", e))
204
- : yield this.config.feeEstimator.estimateFee();
205
- if (feeRate == null)
206
- return null;
207
- let satsPerVbyte = new BN(Math.ceil(feeRate));
208
- if (multiplierPPM != null)
209
- satsPerVbyte = satsPerVbyte.mul(multiplierPPM).div(new BN(1000000));
210
- const utxoPool = yield this.getUtxoPool(estimate);
211
- let obj = (0, coinselect2_1.coinSelect)(utxoPool, [{
212
- address: targetAddress,
213
- value: targetAmount,
214
- script: bitcoin.address.toOutputScript(targetAddress, this.config.bitcoinNetwork)
215
- }], satsPerVbyte.toNumber(), this.LND_CHANGE_OUTPUT_TYPE);
216
- if (obj.inputs == null || obj.outputs == null)
217
- return null;
218
- if (!(yield this.isLeavingEnoughForLightningAnchors(utxoPool, obj, satsPerVbyte, estimate)))
219
- return null;
220
- this.logger.info("getChainFee(): fee estimated," +
221
- " target: " + targetAddress +
222
- " amount: " + targetAmount.toString(10) +
223
- " fee: " + obj.fee +
224
- " sats/vB: " + satsPerVbyte +
225
- " inputs: " + obj.inputs.length +
226
- " outputs: " + obj.outputs.length +
227
- " multiplier: " + (multiplierPPM == null ? 1 : multiplierPPM.toNumber() / 1000000));
228
- return {
229
- networkFee: new BN(obj.fee),
230
- satsPerVbyte,
231
- outputs: obj.outputs,
232
- inputs: obj.inputs
233
- };
234
- });
235
- }
236
51
  /**
237
52
  * Tries to claim the swap after our transaction was confirmed
238
53
  *
239
54
  * @param tx
240
- * @param payment
55
+ * @param swap
241
56
  * @param vout
242
57
  */
243
58
  tryClaimSwap(tx, swap, vout) {
@@ -268,9 +83,8 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
268
83
  processPastSwap(swap) {
269
84
  return __awaiter(this, void 0, void 0, function* () {
270
85
  const { swapContract, signer } = this.getChain(swap.chainIdentifier);
271
- const timestamp = new BN(Math.floor(Date.now() / 1000)).sub(new BN(this.config.maxSkew));
272
- if (swap.state === ToBtcSwapAbs_1.ToBtcSwapState.SAVED && swap.signatureExpiry != null) {
273
- const isSignatureExpired = swap.signatureExpiry.lt(timestamp);
86
+ if (swap.state === ToBtcSwapAbs_1.ToBtcSwapState.SAVED) {
87
+ const isSignatureExpired = swapContract.isInitAuthorizationExpired(swap.data, swap);
274
88
  if (isSignatureExpired) {
275
89
  const isCommitted = yield swapContract.isCommited(swap.data);
276
90
  if (!isCommitted) {
@@ -286,8 +100,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
286
100
  }
287
101
  }
288
102
  if (swap.state === ToBtcSwapAbs_1.ToBtcSwapState.NON_PAYABLE || swap.state === ToBtcSwapAbs_1.ToBtcSwapState.SAVED) {
289
- const isSwapExpired = swap.data.getExpiry().lt(timestamp);
290
- if (isSwapExpired) {
103
+ if (swapContract.isExpired(signer.getAddress(), swap.data)) {
291
104
  this.swapLogger.info(swap, "processPastSwap(state=NON_PAYABLE|SAVED): swap expired, cancelling, address: " + swap.address);
292
105
  yield this.removeSwapData(swap, ToBtcSwapAbs_1.ToBtcSwapState.CANCELED);
293
106
  return;
@@ -349,7 +162,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
349
162
  }
350
163
  this.swapLogger.debug(swap, "processBtcTx(): address: " + swap.address + " amount: " + swap.amount.toString(10) + " btcTx: " + tx);
351
164
  //Search for required transaction output (vout)
352
- const outputScript = bitcoin.address.toOutputScript(swap.address, this.config.bitcoinNetwork);
165
+ const outputScript = this.bitcoin.toOutputScript(swap.address);
353
166
  const vout = tx.outs.find(e => new BN(e.value).eq(swap.amount) && Buffer.from(e.scriptPubKey.hex, "hex").equals(outputScript));
354
167
  if (vout == null) {
355
168
  this.swapLogger.warn(swap, "processBtcTx(): cannot find correct vout," +
@@ -374,7 +187,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
374
187
  const swap = this.activeSubscriptions[txId];
375
188
  //TODO: RBF the transaction if it's already taking too long to confirm
376
189
  try {
377
- let tx = yield this.bitcoinRpc.getTransaction(txId);
190
+ let tx = yield this.bitcoin.getWalletTransaction(txId);
378
191
  if (tx == null)
379
192
  continue;
380
193
  if (yield this.processBtcTx(swap, tx)) {
@@ -445,117 +258,11 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
445
258
  code: 90003,
446
259
  msg: "Fee changed too much!",
447
260
  data: {
448
- quotedFee: actualSatsPerVbyte.toString(10),
449
- actualFee: quotedSatsPerVbyte.toString(10)
261
+ quotedFee: quotedSatsPerVbyte.toString(10),
262
+ actualFee: actualSatsPerVbyte.toString(10)
450
263
  }
451
264
  };
452
265
  }
453
- /**
454
- * Runs sanity check on the calculated fee for the transaction
455
- *
456
- * @param psbt
457
- * @param tx
458
- * @param maxAllowedSatsPerVbyte
459
- * @param actualSatsPerVbyte
460
- * @private
461
- * @throws {Error} Will throw an error if the fee sanity check doesn't pass
462
- */
463
- checkPsbtFee(psbt, tx, maxAllowedSatsPerVbyte, actualSatsPerVbyte) {
464
- const txFee = new BN(psbt.getFee());
465
- //Sanity check on sats/vB
466
- const maxAllowedFee = new BN(tx.virtualSize())
467
- //Considering the extra output was not added, because was detrminetal
468
- .add(new BN(utils_1.utils.outputBytes({ type: this.LND_CHANGE_OUTPUT_TYPE })))
469
- //Multiply by maximum allowed feerate
470
- .mul(maxAllowedSatsPerVbyte)
471
- //Possibility that extra output was not added due to it being lower than dust
472
- .add(new BN(utils_1.utils.dustThreshold({ type: this.LND_CHANGE_OUTPUT_TYPE })));
473
- if (txFee.gt(maxAllowedFee))
474
- throw new Error("Generated tx fee too high: " + JSON.stringify({
475
- maxAllowedFee: maxAllowedFee.toString(10),
476
- actualFee: txFee.toString(10),
477
- psbtHex: psbt.toHex(),
478
- maxAllowedSatsPerVbyte: maxAllowedSatsPerVbyte.toString(10),
479
- actualSatsPerVbyte: actualSatsPerVbyte.toString(10)
480
- }));
481
- return txFee;
482
- }
483
- /**
484
- * Create PSBT for swap payout from coinselection result
485
- *
486
- * @param address
487
- * @param amount
488
- * @param escrowNonce
489
- * @param coinselectResult
490
- * @private
491
- */
492
- getPsbt(address, amount, escrowNonce, coinselectResult) {
493
- return __awaiter(this, void 0, void 0, function* () {
494
- let psbt = new bitcoin.Psbt();
495
- //Apply nonce
496
- const nonceBuffer = Buffer.from(escrowNonce.toArray("be", 8));
497
- const locktimeBN = new BN(nonceBuffer.slice(0, 5), "be");
498
- let locktime = locktimeBN.toNumber() + 500000000;
499
- psbt.setLocktime(locktime);
500
- const sequenceBN = new BN(nonceBuffer.slice(5, 8), "be");
501
- const sequence = 0xFE000000 + sequenceBN.toNumber();
502
- psbt.addInputs(coinselectResult.inputs.map(input => {
503
- return {
504
- hash: input.txId,
505
- index: input.vout,
506
- witnessUtxo: {
507
- script: input.outputScript,
508
- value: input.value
509
- },
510
- sighashType: 0x01,
511
- sequence
512
- };
513
- }));
514
- psbt.addOutput({
515
- script: bitcoin.address.toOutputScript(address, this.config.bitcoinNetwork),
516
- value: amount.toNumber()
517
- });
518
- //Add change output
519
- if (coinselectResult.outputs.length > 1)
520
- psbt.addOutput({
521
- script: bitcoin.address.toOutputScript(yield this.getChangeAddress(), this.config.bitcoinNetwork),
522
- value: coinselectResult.outputs[1].value
523
- });
524
- return psbt;
525
- });
526
- }
527
- /**
528
- * Signs provided PSBT and also returns a raw signed transaction
529
- *
530
- * @param psbt
531
- * @private
532
- */
533
- signPsbt(psbt) {
534
- return __awaiter(this, void 0, void 0, function* () {
535
- const signedPsbt = yield lncli.signPsbt({
536
- lnd: this.LND,
537
- psbt: psbt.toHex()
538
- });
539
- return {
540
- psbt: bitcoin.Psbt.fromHex(signedPsbt.psbt),
541
- rawTx: signedPsbt.transaction
542
- };
543
- });
544
- }
545
- /**
546
- * Sends raw bitcoin transaction
547
- *
548
- * @param rawTx
549
- * @private
550
- */
551
- sendRawTransaction(rawTx) {
552
- return __awaiter(this, void 0, void 0, function* () {
553
- yield lncli.broadcastChainTransaction({
554
- lnd: this.LND,
555
- transaction: rawTx
556
- });
557
- });
558
- }
559
266
  /**
560
267
  * Sends a bitcoin transaction to payout BTC for a swap
561
268
  *
@@ -571,35 +278,27 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
571
278
  this.checkExpiresTooSoon(swap);
572
279
  if (swap.metadata != null)
573
280
  swap.metadata.times.payCLTVChecked = Date.now();
574
- const coinselectResult = yield this.getChainFee(swap.address, swap.amount.toNumber());
575
- if (coinselectResult == null)
281
+ const satsPerVbyte = yield this.bitcoin.getFeeRate();
282
+ this.checkCalculatedTxFee(swap.satsPerVbyte, new BN(satsPerVbyte));
283
+ if (swap.metadata != null)
284
+ swap.metadata.times.payChainFee = Date.now();
285
+ const signResult = yield this.bitcoin.getSignedTransaction(swap.address, swap.amount.toNumber(), satsPerVbyte, swap.data.getEscrowNonce(), swap.satsPerVbyte.toNumber());
286
+ if (signResult == null)
576
287
  throw {
577
288
  code: 90002,
578
- msg: "Failed to run coinselect algorithm (not enough funds?)"
289
+ msg: "Failed to create signed transaction (not enough funds?)"
579
290
  };
580
- if (swap.metadata != null)
581
- swap.metadata.times.payChainFee = Date.now();
582
- this.checkCalculatedTxFee(swap.satsPerVbyte, coinselectResult.satsPerVbyte);
583
- //Construct payment PSBT
584
- let unsignedPsbt = yield this.getPsbt(swap.address, swap.amount, swap.data.getEscrowNonce(), coinselectResult);
585
- this.swapLogger.debug(swap, "sendBitcoinPayment(): generated psbt: " + unsignedPsbt.toHex());
586
- //Sign the PSBT
587
- const { psbt, rawTx } = yield this.signPsbt(unsignedPsbt);
588
291
  if (swap.metadata != null)
589
292
  swap.metadata.times.paySignPSBT = Date.now();
590
- this.swapLogger.debug(swap, "sendBitcoinPayment(): signed raw transaction: " + rawTx);
591
- const tx = bitcoin.Transaction.fromHex(rawTx);
592
- const txFee = this.checkPsbtFee(psbt, tx, swap.satsPerVbyte, coinselectResult.satsPerVbyte);
593
- swap.txId = tx.getId();
594
- swap.setRealNetworkFee(txFee);
293
+ this.swapLogger.debug(swap, "sendBitcoinPayment(): signed raw transaction: " + signResult.raw);
294
+ swap.txId = signResult.tx.getId();
295
+ swap.setRealNetworkFee(new BN(signResult.networkFee));
595
296
  yield swap.setState(ToBtcSwapAbs_1.ToBtcSwapState.BTC_SENDING);
596
297
  yield this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
597
- yield this.sendRawTransaction(rawTx);
298
+ yield this.bitcoin.sendRawTransaction(signResult.raw);
598
299
  if (swap.metadata != null)
599
300
  swap.metadata.times.payTxSent = Date.now();
600
- this.swapLogger.info(swap, "sendBitcoinPayment(): btc transaction generated, signed & broadcasted, txId: " + tx.getId() + " address: " + swap.address);
601
- //Invalidate the UTXO cache
602
- this.cachedUtxos = null;
301
+ this.swapLogger.info(swap, "sendBitcoinPayment(): btc transaction generated, signed & broadcasted, txId: " + signResult.tx.getId() + " address: " + swap.address);
603
302
  yield swap.setState(ToBtcSwapAbs_1.ToBtcSwapState.BTC_SENT);
604
303
  yield this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
605
304
  }));
@@ -613,7 +312,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
613
312
  return __awaiter(this, void 0, void 0, function* () {
614
313
  if (swap.state === ToBtcSwapAbs_1.ToBtcSwapState.BTC_SENDING) {
615
314
  //Bitcoin transaction was signed (maybe also sent)
616
- const tx = yield this.bitcoinRpc.getTransaction(swap.txId);
315
+ const tx = yield this.bitcoin.getWalletTransaction(swap.txId);
617
316
  const isTxSent = tx != null;
618
317
  if (!isTxSent) {
619
318
  //Reset the state to COMMITED
@@ -782,7 +481,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
782
481
  checkAddress(address) {
783
482
  let parsedOutputScript;
784
483
  try {
785
- parsedOutputScript = bitcoin.address.toOutputScript(address, this.config.bitcoinNetwork);
484
+ parsedOutputScript = this.bitcoin.toOutputScript(address);
786
485
  }
787
486
  catch (e) {
788
487
  throw {
@@ -803,7 +502,8 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
803
502
  * @throws {DefinedRuntimeError} will throw an error if the swap is expired
804
503
  */
805
504
  checkExpired(swap) {
806
- const isExpired = swap.data.getExpiry().lt(new BN(Math.floor(Date.now() / 1000)).sub(new BN(this.config.maxSkew)));
505
+ const { swapContract, signer } = this.getChain(swap.chainIdentifier);
506
+ const isExpired = swapContract.isExpired(signer.getAddress(), swap.data);
807
507
  if (isExpired)
808
508
  throw {
809
509
  _httpStatus: 200,
@@ -820,14 +520,17 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
820
520
  */
821
521
  checkAndGetNetworkFee(address, amount) {
822
522
  return __awaiter(this, void 0, void 0, function* () {
823
- let chainFeeResp = yield this.getChainFee(address, amount.toNumber(), true, this.config.networkFeeMultiplierPPM);
523
+ let chainFeeResp = yield this.bitcoin.estimateFee(address, amount.toNumber(), null, this.config.networkFeeMultiplier);
824
524
  const hasEnoughFunds = chainFeeResp != null;
825
525
  if (!hasEnoughFunds)
826
526
  throw {
827
527
  code: 20002,
828
528
  msg: "Not enough liquidity"
829
529
  };
830
- return chainFeeResp;
530
+ return {
531
+ networkFee: new BN(chainFeeResp.networkFee),
532
+ satsPerVbyte: new BN(chainFeeResp.satsPerVbyte)
533
+ };
831
534
  });
832
535
  }
833
536
  startRestServer(restServer) {
@@ -898,7 +601,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
898
601
  return resp;
899
602
  }), abortController.signal, pricePrefetchPromise);
900
603
  metadata.times.priceCalculated = Date.now();
901
- const paymentHash = this.getHash(chainIdentifier, parsedBody.address, parsedBody.nonce, amountBD, this.config.bitcoinNetwork).toString("hex");
604
+ const paymentHash = this.getHash(chainIdentifier, parsedBody.address, parsedBody.nonce, amountBD).toString("hex");
902
605
  //Add grace period another time, so the user has 1 hour to commit
903
606
  const expirySeconds = this.getExpiryFromCLTV(parsedBody.confirmationTarget, parsedBody.confirmations).add(new BN(this.config.gracePeriod));
904
607
  const currentTimestamp = new BN(Math.floor(Date.now() / 1000));
@@ -909,9 +612,13 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
909
612
  metadata.times.swapCreated = Date.now();
910
613
  const sigData = yield this.getToBtcSignatureData(chainIdentifier, payObject, req, abortController.signal, signDataPrefetchPromise);
911
614
  metadata.times.swapSigned = Date.now();
912
- const createdSwap = new ToBtcSwapAbs_1.ToBtcSwapAbs(chainIdentifier, parsedBody.address, amountBD, swapFee, swapFeeInToken, networkFeeData.networkFee, networkFeeInToken, networkFeeData.satsPerVbyte, parsedBody.nonce, parsedBody.confirmationTarget, new BN(sigData.timeout));
615
+ const createdSwap = new ToBtcSwapAbs_1.ToBtcSwapAbs(chainIdentifier, parsedBody.address, amountBD, swapFee, swapFeeInToken, networkFeeData.networkFee, networkFeeInToken, networkFeeData.satsPerVbyte, parsedBody.nonce, parsedBody.confirmationTarget);
913
616
  createdSwap.data = payObject;
914
617
  createdSwap.metadata = metadata;
618
+ createdSwap.prefix = sigData.prefix;
619
+ createdSwap.timeout = sigData.timeout;
620
+ createdSwap.signature = sigData.signature;
621
+ createdSwap.feeRate = sigData.feeRate;
915
622
  yield PluginManager_1.PluginManager.swapCreate(createdSwap);
916
623
  yield this.storageManager.saveData(paymentHash, sequence, createdSwap);
917
624
  this.swapLogger.info(createdSwap, "REST: /payInvoice: created swap address: " + createdSwap.address + " amount: " + amountBD.toString(10));
@@ -959,7 +666,6 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
959
666
  code: 20007,
960
667
  msg: "Payment not found"
961
668
  };
962
- const { swapContract, signer } = this.getChain(payment.chainIdentifier);
963
669
  this.checkExpired(payment);
964
670
  if (payment.state === ToBtcSwapAbs_1.ToBtcSwapState.COMMITED)
965
671
  throw {
@@ -976,6 +682,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
976
682
  txId: payment.txId
977
683
  }
978
684
  };
685
+ const { swapContract, signer } = this.getChain(payment.chainIdentifier);
979
686
  if (payment.state === ToBtcSwapAbs_1.ToBtcSwapState.NON_PAYABLE) {
980
687
  const isCommited = yield swapContract.isCommited(payment.data);
981
688
  if (!isCommited)
@@ -13,17 +13,14 @@ export declare enum ToBtcSwapState {
13
13
  }
14
14
  export declare class ToBtcSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap<T, ToBtcSwapState> {
15
15
  readonly address: string;
16
- readonly amount: BN;
17
16
  readonly satsPerVbyte: BN;
18
17
  readonly nonce: BN;
19
18
  readonly preferedConfirmationTarget: number;
20
- readonly signatureExpiry: BN;
21
19
  txId: string;
22
- constructor(chainIdentifier: string, address: string, amount: BN, swapFee: BN, swapFeeInToken: BN, networkFee: BN, networkFeeInToken: BN, satsPerVbyte: BN, nonce: BN, preferedConfirmationTarget: number, signatureExpiry: BN);
20
+ constructor(chainIdentifier: string, address: string, amount: BN, swapFee: BN, swapFeeInToken: BN, networkFee: BN, networkFeeInToken: BN, satsPerVbyte: BN, nonce: BN, preferedConfirmationTarget: number);
23
21
  constructor(obj: any);
24
22
  serialize(): any;
25
23
  isInitiated(): boolean;
26
24
  isFailed(): boolean;
27
25
  isSuccess(): boolean;
28
- getOutputAmount(): BN;
29
26
  }
@@ -17,26 +17,22 @@ var ToBtcSwapState;
17
17
  ToBtcSwapState[ToBtcSwapState["CLAIMED"] = 4] = "CLAIMED";
18
18
  })(ToBtcSwapState = exports.ToBtcSwapState || (exports.ToBtcSwapState = {}));
19
19
  class ToBtcSwapAbs extends ToBtcBaseSwap_1.ToBtcBaseSwap {
20
- constructor(chainIdOrObj, address, amount, swapFee, swapFeeInToken, networkFee, networkFeeInToken, satsPerVbyte, nonce, preferedConfirmationTarget, signatureExpiry) {
20
+ constructor(chainIdOrObj, address, amount, swapFee, swapFeeInToken, networkFee, networkFeeInToken, satsPerVbyte, nonce, preferedConfirmationTarget) {
21
21
  var _a;
22
22
  if (typeof (chainIdOrObj) === "string") {
23
- super(chainIdOrObj, swapFee, swapFeeInToken, networkFee, networkFeeInToken);
23
+ super(chainIdOrObj, amount, swapFee, swapFeeInToken, networkFee, networkFeeInToken);
24
24
  this.state = ToBtcSwapState.SAVED;
25
25
  this.address = address;
26
- this.amount = amount;
27
26
  this.satsPerVbyte = satsPerVbyte;
28
27
  this.nonce = nonce;
29
28
  this.preferedConfirmationTarget = preferedConfirmationTarget;
30
- this.signatureExpiry = signatureExpiry;
31
29
  }
32
30
  else {
33
31
  super(chainIdOrObj);
34
32
  this.address = chainIdOrObj.address;
35
- this.amount = new BN(chainIdOrObj.amount);
36
33
  this.satsPerVbyte = new BN(chainIdOrObj.satsPerVbyte);
37
34
  this.nonce = new BN(chainIdOrObj.nonce);
38
35
  this.preferedConfirmationTarget = chainIdOrObj.preferedConfirmationTarget;
39
- this.signatureExpiry = (0, Utils_1.deserializeBN)(chainIdOrObj.signatureExpiry);
40
36
  this.txId = chainIdOrObj.txId;
41
37
  //Compatibility
42
38
  (_a = this.quotedNetworkFee) !== null && _a !== void 0 ? _a : (this.quotedNetworkFee = (0, Utils_1.deserializeBN)(chainIdOrObj.networkFee));
@@ -46,11 +42,9 @@ class ToBtcSwapAbs extends ToBtcBaseSwap_1.ToBtcBaseSwap {
46
42
  serialize() {
47
43
  const partialSerialized = super.serialize();
48
44
  partialSerialized.address = this.address;
49
- partialSerialized.amount = this.amount.toString(10);
50
45
  partialSerialized.satsPerVbyte = this.satsPerVbyte.toString(10);
51
46
  partialSerialized.nonce = this.nonce.toString(10);
52
47
  partialSerialized.preferedConfirmationTarget = this.preferedConfirmationTarget;
53
- partialSerialized.signatureExpiry = (0, Utils_1.serializeBN)(this.signatureExpiry);
54
48
  partialSerialized.txId = this.txId;
55
49
  return partialSerialized;
56
50
  }
@@ -63,8 +57,5 @@ class ToBtcSwapAbs extends ToBtcBaseSwap_1.ToBtcBaseSwap {
63
57
  isSuccess() {
64
58
  return this.state === ToBtcSwapState.CLAIMED;
65
59
  }
66
- getOutputAmount() {
67
- return this.amount;
68
- }
69
60
  }
70
61
  exports.ToBtcSwapAbs = ToBtcSwapAbs;