@atomiqlabs/lp-lib 10.3.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.
Files changed (138) hide show
  1. package/LICENSE +201 -0
  2. package/dist/fees/IBtcFeeEstimator.d.ts +3 -0
  3. package/dist/fees/IBtcFeeEstimator.js +2 -0
  4. package/dist/fees/OneDollarFeeEstimator.d.ts +16 -0
  5. package/dist/fees/OneDollarFeeEstimator.js +71 -0
  6. package/dist/index.d.ts +33 -0
  7. package/dist/index.js +52 -0
  8. package/dist/info/InfoHandler.d.ts +17 -0
  9. package/dist/info/InfoHandler.js +70 -0
  10. package/dist/plugins/IPlugin.d.ts +118 -0
  11. package/dist/plugins/IPlugin.js +33 -0
  12. package/dist/plugins/PluginManager.d.ts +89 -0
  13. package/dist/plugins/PluginManager.js +263 -0
  14. package/dist/prices/BinanceSwapPrice.d.ts +27 -0
  15. package/dist/prices/BinanceSwapPrice.js +106 -0
  16. package/dist/prices/CoinGeckoSwapPrice.d.ts +31 -0
  17. package/dist/prices/CoinGeckoSwapPrice.js +76 -0
  18. package/dist/storage/IIntermediaryStorage.d.ts +15 -0
  19. package/dist/storage/IIntermediaryStorage.js +2 -0
  20. package/dist/storagemanager/IntermediaryStorageManager.d.ts +15 -0
  21. package/dist/storagemanager/IntermediaryStorageManager.js +113 -0
  22. package/dist/storagemanager/StorageManager.d.ts +12 -0
  23. package/dist/storagemanager/StorageManager.js +74 -0
  24. package/dist/swaps/FromBtcBaseSwap.d.ts +12 -0
  25. package/dist/swaps/FromBtcBaseSwap.js +16 -0
  26. package/dist/swaps/FromBtcBaseSwapHandler.d.ts +118 -0
  27. package/dist/swaps/FromBtcBaseSwapHandler.js +294 -0
  28. package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +25 -0
  29. package/dist/swaps/FromBtcLnBaseSwapHandler.js +55 -0
  30. package/dist/swaps/ISwapPrice.d.ts +44 -0
  31. package/dist/swaps/ISwapPrice.js +73 -0
  32. package/dist/swaps/SwapHandler.d.ts +186 -0
  33. package/dist/swaps/SwapHandler.js +292 -0
  34. package/dist/swaps/SwapHandlerSwap.d.ts +75 -0
  35. package/dist/swaps/SwapHandlerSwap.js +72 -0
  36. package/dist/swaps/ToBtcBaseSwap.d.ts +35 -0
  37. package/dist/swaps/ToBtcBaseSwap.js +61 -0
  38. package/dist/swaps/ToBtcBaseSwapHandler.d.ts +94 -0
  39. package/dist/swaps/ToBtcBaseSwapHandler.js +233 -0
  40. package/dist/swaps/frombtc_abstract/FromBtcAbs.d.ts +92 -0
  41. package/dist/swaps/frombtc_abstract/FromBtcAbs.js +386 -0
  42. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.d.ts +26 -0
  43. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.js +63 -0
  44. package/dist/swaps/frombtc_trusted/FromBtcTrusted.d.ts +55 -0
  45. package/dist/swaps/frombtc_trusted/FromBtcTrusted.js +586 -0
  46. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.d.ts +43 -0
  47. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.js +99 -0
  48. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.d.ts +105 -0
  49. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.js +731 -0
  50. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +29 -0
  51. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.js +64 -0
  52. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.d.ts +79 -0
  53. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.js +514 -0
  54. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.d.ts +28 -0
  55. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.js +66 -0
  56. package/dist/swaps/tobtc_abstract/ToBtcAbs.d.ts +290 -0
  57. package/dist/swaps/tobtc_abstract/ToBtcAbs.js +1056 -0
  58. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.d.ts +29 -0
  59. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.js +70 -0
  60. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.d.ts +246 -0
  61. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.js +1169 -0
  62. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.d.ts +27 -0
  63. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.js +65 -0
  64. package/dist/utils/Utils.d.ts +32 -0
  65. package/dist/utils/Utils.js +109 -0
  66. package/dist/utils/coinselect2/accumulative.d.ts +6 -0
  67. package/dist/utils/coinselect2/accumulative.js +44 -0
  68. package/dist/utils/coinselect2/blackjack.d.ts +6 -0
  69. package/dist/utils/coinselect2/blackjack.js +41 -0
  70. package/dist/utils/coinselect2/index.d.ts +16 -0
  71. package/dist/utils/coinselect2/index.js +40 -0
  72. package/dist/utils/coinselect2/utils.d.ts +64 -0
  73. package/dist/utils/coinselect2/utils.js +121 -0
  74. package/dist/utils/paramcoders/IParamReader.d.ts +5 -0
  75. package/dist/utils/paramcoders/IParamReader.js +2 -0
  76. package/dist/utils/paramcoders/IParamWriter.d.ts +4 -0
  77. package/dist/utils/paramcoders/IParamWriter.js +2 -0
  78. package/dist/utils/paramcoders/LegacyParamEncoder.d.ts +10 -0
  79. package/dist/utils/paramcoders/LegacyParamEncoder.js +33 -0
  80. package/dist/utils/paramcoders/ParamDecoder.d.ts +25 -0
  81. package/dist/utils/paramcoders/ParamDecoder.js +234 -0
  82. package/dist/utils/paramcoders/ParamEncoder.d.ts +9 -0
  83. package/dist/utils/paramcoders/ParamEncoder.js +22 -0
  84. package/dist/utils/paramcoders/SchemaVerifier.d.ts +22 -0
  85. package/dist/utils/paramcoders/SchemaVerifier.js +85 -0
  86. package/dist/utils/paramcoders/server/ServerParamDecoder.d.ts +8 -0
  87. package/dist/utils/paramcoders/server/ServerParamDecoder.js +105 -0
  88. package/dist/utils/paramcoders/server/ServerParamEncoder.d.ts +11 -0
  89. package/dist/utils/paramcoders/server/ServerParamEncoder.js +76 -0
  90. package/package.json +43 -0
  91. package/src/fees/IBtcFeeEstimator.ts +7 -0
  92. package/src/fees/OneDollarFeeEstimator.ts +95 -0
  93. package/src/index.ts +46 -0
  94. package/src/info/InfoHandler.ts +106 -0
  95. package/src/plugins/IPlugin.ts +155 -0
  96. package/src/plugins/PluginManager.ts +310 -0
  97. package/src/prices/BinanceSwapPrice.ts +114 -0
  98. package/src/prices/CoinGeckoSwapPrice.ts +88 -0
  99. package/src/storage/IIntermediaryStorage.ts +21 -0
  100. package/src/storagemanager/IntermediaryStorageManager.ts +101 -0
  101. package/src/storagemanager/StorageManager.ts +68 -0
  102. package/src/swaps/FromBtcBaseSwap.ts +21 -0
  103. package/src/swaps/FromBtcBaseSwapHandler.ts +375 -0
  104. package/src/swaps/FromBtcLnBaseSwapHandler.ts +48 -0
  105. package/src/swaps/ISwapPrice.ts +94 -0
  106. package/src/swaps/SwapHandler.ts +404 -0
  107. package/src/swaps/SwapHandlerSwap.ts +133 -0
  108. package/src/swaps/ToBtcBaseSwap.ts +76 -0
  109. package/src/swaps/ToBtcBaseSwapHandler.ts +309 -0
  110. package/src/swaps/frombtc_abstract/FromBtcAbs.ts +484 -0
  111. package/src/swaps/frombtc_abstract/FromBtcSwapAbs.ts +77 -0
  112. package/src/swaps/frombtc_trusted/FromBtcTrusted.ts +661 -0
  113. package/src/swaps/frombtc_trusted/FromBtcTrustedSwap.ts +158 -0
  114. package/src/swaps/frombtcln_abstract/FromBtcLnAbs.ts +864 -0
  115. package/src/swaps/frombtcln_abstract/FromBtcLnSwapAbs.ts +82 -0
  116. package/src/swaps/frombtcln_trusted/FromBtcLnTrusted.ts +592 -0
  117. package/src/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.ts +90 -0
  118. package/src/swaps/tobtc_abstract/ToBtcAbs.ts +1249 -0
  119. package/src/swaps/tobtc_abstract/ToBtcSwapAbs.ts +112 -0
  120. package/src/swaps/tobtcln_abstract/ToBtcLnAbs.ts +1422 -0
  121. package/src/swaps/tobtcln_abstract/ToBtcLnSwapAbs.ts +87 -0
  122. package/src/utils/Utils.ts +108 -0
  123. package/src/utils/coinselect2/accumulative.js +32 -0
  124. package/src/utils/coinselect2/accumulative.ts +58 -0
  125. package/src/utils/coinselect2/blackjack.js +29 -0
  126. package/src/utils/coinselect2/blackjack.ts +54 -0
  127. package/src/utils/coinselect2/index.js +16 -0
  128. package/src/utils/coinselect2/index.ts +50 -0
  129. package/src/utils/coinselect2/utils.js +110 -0
  130. package/src/utils/coinselect2/utils.ts +183 -0
  131. package/src/utils/paramcoders/IParamReader.ts +8 -0
  132. package/src/utils/paramcoders/IParamWriter.ts +8 -0
  133. package/src/utils/paramcoders/LegacyParamEncoder.ts +28 -0
  134. package/src/utils/paramcoders/ParamDecoder.ts +219 -0
  135. package/src/utils/paramcoders/ParamEncoder.ts +30 -0
  136. package/src/utils/paramcoders/SchemaVerifier.ts +97 -0
  137. package/src/utils/paramcoders/server/ServerParamDecoder.ts +115 -0
  138. package/src/utils/paramcoders/server/ServerParamEncoder.ts +76 -0
@@ -0,0 +1,586 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FromBtcTrusted = void 0;
13
+ const FromBtcBaseSwapHandler_1 = require("../FromBtcBaseSwapHandler");
14
+ const FromBtcTrustedSwap_1 = require("./FromBtcTrustedSwap");
15
+ const SwapHandler_1 = require("../SwapHandler");
16
+ const BN = require("bn.js");
17
+ const lightning_1 = require("lightning");
18
+ const PluginManager_1 = require("../../plugins/PluginManager");
19
+ const bitcoinjs_lib_1 = require("bitcoinjs-lib");
20
+ const utils_1 = require("../../utils/coinselect2/utils");
21
+ const Utils_1 = require("../../utils/Utils");
22
+ const SchemaVerifier_1 = require("../../utils/paramcoders/SchemaVerifier");
23
+ const bitcoin = require("bitcoinjs-lib");
24
+ const ServerParamDecoder_1 = require("../../utils/paramcoders/server/ServerParamDecoder");
25
+ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
26
+ constructor(storageDirectory, path, chains, lnd, swapPricing, bitcoinRpc, config) {
27
+ var _a;
28
+ var _b;
29
+ super(storageDirectory, path, chains, lnd, swapPricing);
30
+ this.type = SwapHandler_1.SwapHandlerType.FROM_BTC_TRUSTED;
31
+ this.subscriptions = new Map();
32
+ this.doubleSpendWatchdogSwaps = new Set();
33
+ this.refundedSwaps = new Map();
34
+ this.doubleSpentSwaps = new Map();
35
+ this.processedTxIds = new Map();
36
+ this.config = config;
37
+ (_a = (_b = this.config).recommendFeeMultiplier) !== null && _a !== void 0 ? _a : (_b.recommendFeeMultiplier = 1.25);
38
+ this.bitcoinRpc = bitcoinRpc;
39
+ for (let chainId in chains.chains) {
40
+ this.allowedTokens[chainId] = new Set([chains.chains[chainId].swapContract.getNativeCurrencyAddress()]);
41
+ }
42
+ }
43
+ getAllAncestors(tx) {
44
+ return Promise.all(tx.inputs.map(input => this.bitcoinRpc.getTransaction(input.transaction_id).then(tx => {
45
+ return { tx, vout: input.transaction_vout };
46
+ })));
47
+ }
48
+ refundSwap(swap) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ let unlock = swap.lock(30 * 1000);
51
+ if (unlock == null)
52
+ return;
53
+ const feeRate = yield this.config.feeEstimator.estimateFee();
54
+ const initialTx = bitcoinjs_lib_1.Transaction.fromHex(swap.rawTx);
55
+ const ourOutput = initialTx.outs[swap.vout];
56
+ //Construct PSBT
57
+ const refundOutputScript = bitcoinjs_lib_1.address.toOutputScript(swap.refundAddress, this.config.bitcoinNetwork);
58
+ const txBytes = utils_1.utils.transactionBytes([{ type: "p2wpkh" }], [{ script: refundOutputScript }], "p2wpkh");
59
+ const txFee = txBytes * feeRate;
60
+ const adjustedOutput = ourOutput.value - txFee;
61
+ if (adjustedOutput < 546) {
62
+ this.swapLogger.error(swap, "refundSwap(): cannot refund swap because of dust limit, txId: " + swap.txId);
63
+ unlock();
64
+ return;
65
+ }
66
+ //Construct PSBT
67
+ const _psbt = new bitcoinjs_lib_1.Psbt({ network: this.config.bitcoinNetwork });
68
+ _psbt.addInput({
69
+ hash: initialTx.getHash(),
70
+ index: swap.vout,
71
+ witnessUtxo: ourOutput,
72
+ sighashType: 0x01,
73
+ sequence: 0xfffffffd
74
+ });
75
+ _psbt.addOutput({
76
+ script: refundOutputScript,
77
+ value: adjustedOutput
78
+ });
79
+ //Sign
80
+ const { psbt, transaction } = yield (0, lightning_1.signPsbt)({
81
+ lnd: this.LND,
82
+ psbt: _psbt.toHex()
83
+ });
84
+ if (swap.metadata != null)
85
+ swap.metadata.times.refundSignPSBT = Date.now();
86
+ this.swapLogger.debug(swap, "refundSwap(): signed raw transaction: " + transaction);
87
+ const signedTx = bitcoinjs_lib_1.Transaction.fromHex(transaction);
88
+ const refundTxId = signedTx.getId();
89
+ swap.refundTxId = refundTxId;
90
+ //Send the refund TX
91
+ yield (0, lightning_1.broadcastChainTransaction)({ transaction, lnd: this.LND });
92
+ this.swapLogger.debug(swap, "refundSwap(): sent refund transaction: " + refundTxId);
93
+ this.refundedSwaps.set(swap.getHash(), refundTxId);
94
+ yield this.removeSwapData(swap, FromBtcTrustedSwap_1.FromBtcTrustedSwapState.REFUNDED);
95
+ unlock();
96
+ });
97
+ }
98
+ burn(swap) {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ const initialTx = bitcoinjs_lib_1.Transaction.fromHex(swap.rawTx);
101
+ const ourOutput = initialTx.outs[swap.vout];
102
+ //Construct PSBT
103
+ const _psbt = new bitcoinjs_lib_1.Psbt({ network: this.config.bitcoinNetwork });
104
+ _psbt.addInput({
105
+ hash: initialTx.getHash(),
106
+ index: swap.vout,
107
+ witnessUtxo: ourOutput,
108
+ sighashType: 0x01,
109
+ sequence: 0xfffffffd
110
+ });
111
+ _psbt.addOutput({
112
+ script: Buffer.concat([Buffer.from([0x6a, 20]), Buffer.from("BURN, BABY, BURN! AQ", "ascii")]),
113
+ value: 0
114
+ });
115
+ //Sign
116
+ const { psbt, transaction } = yield (0, lightning_1.signPsbt)({
117
+ lnd: this.LND,
118
+ psbt: _psbt.toHex()
119
+ });
120
+ if (swap.metadata != null)
121
+ swap.metadata.times.burnSignPSBT = Date.now();
122
+ this.swapLogger.debug(swap, "burn(): signed raw transaction: " + transaction);
123
+ const signedTx = bitcoinjs_lib_1.Transaction.fromHex(transaction);
124
+ const burnTxId = signedTx.getId();
125
+ swap.burnTxId = burnTxId;
126
+ //Send the original TX + our burn TX as a package
127
+ const sendTxns = [swap.rawTx, transaction];
128
+ yield this.bitcoinRpc.sendRawPackage(sendTxns);
129
+ this.swapLogger.debug(swap, "burn(): sent burn transaction: " + burnTxId);
130
+ this.doubleSpentSwaps.set(swap.getHash(), burnTxId);
131
+ yield this.removeSwapData(swap, FromBtcTrustedSwap_1.FromBtcTrustedSwapState.DOUBLE_SPENT);
132
+ });
133
+ }
134
+ processPastSwap(swap, tx) {
135
+ return __awaiter(this, void 0, void 0, function* () {
136
+ let parsedTx = null;
137
+ let foundVout = null;
138
+ let vout = -1;
139
+ if (tx != null) {
140
+ parsedTx = bitcoinjs_lib_1.Transaction.fromHex(tx.transaction);
141
+ const requiredOutputScript = bitcoinjs_lib_1.address.toOutputScript(swap.btcAddress, this.config.bitcoinNetwork);
142
+ vout = parsedTx.outs.findIndex(vout => vout.script.equals(requiredOutputScript));
143
+ if (vout !== -1)
144
+ foundVout = parsedTx.outs[vout];
145
+ }
146
+ const { swapContract, signer } = this.getChain(swap.chainIdentifier);
147
+ if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CREATED) {
148
+ this.subscriptions.set(swap.btcAddress, swap);
149
+ if (foundVout == null) {
150
+ //Check expiry
151
+ if (swap.expiresAt < Date.now()) {
152
+ this.subscriptions.delete(swap.btcAddress);
153
+ yield this.removeSwapData(swap, FromBtcTrustedSwap_1.FromBtcTrustedSwapState.EXPIRED);
154
+ return;
155
+ }
156
+ return;
157
+ }
158
+ const sentSats = new BN(foundVout.value);
159
+ if (sentSats.eq(swap.inputSats)) {
160
+ swap.adjustedInput = swap.inputSats;
161
+ swap.adjustedOutput = swap.outputTokens;
162
+ }
163
+ else {
164
+ //If lower than minimum then ignore
165
+ if (sentSats.lt(this.config.min))
166
+ return;
167
+ if (sentSats.gt(this.config.max)) {
168
+ swap.rawTx = tx.transaction;
169
+ swap.txId = tx.id;
170
+ swap.vout = vout;
171
+ this.subscriptions.delete(swap.btcAddress);
172
+ yield this.refundSwap(swap);
173
+ return;
174
+ }
175
+ //Adjust the amount
176
+ swap.adjustedInput = sentSats;
177
+ swap.adjustedOutput = swap.outputTokens.mul(sentSats).div(swap.inputSats);
178
+ }
179
+ swap.rawTx = tx.transaction;
180
+ swap.txId = tx.id;
181
+ swap.vout = vout;
182
+ this.subscriptions.delete(swap.btcAddress);
183
+ yield swap.setState(FromBtcTrustedSwap_1.FromBtcTrustedSwapState.RECEIVED);
184
+ yield this.storageManager.saveData(swap.getHash(), null, swap);
185
+ }
186
+ if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.RECEIVED) {
187
+ //Check if transaction still exists
188
+ if (tx == null || foundVout == null || tx.id !== swap.txId) {
189
+ yield swap.setState(FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CREATED);
190
+ yield this.storageManager.saveData(swap.getHash(), null, swap);
191
+ return;
192
+ }
193
+ //Check if it is confirmed
194
+ if (tx.confirmation_count > 0) {
195
+ yield swap.setState(FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED);
196
+ yield this.storageManager.saveData(swap.getHash(), null, swap);
197
+ }
198
+ else {
199
+ //Check if it pays high enough fee AND has confirmed ancestors
200
+ const ancestors = yield this.getAllAncestors(tx);
201
+ const allAncestorsConfirmed = ancestors.reduce((prev, curr) => prev && curr.tx.confirmations > 0, true);
202
+ const totalInput = ancestors.reduce((prev, curr) => prev + curr.tx.outs[curr.vout].value, 0);
203
+ const totalOutput = parsedTx.outs.reduce((prev, curr) => prev + curr.value, 0);
204
+ const fee = totalInput - totalOutput;
205
+ const feePerVbyte = Math.ceil(fee / parsedTx.virtualSize());
206
+ if (allAncestorsConfirmed &&
207
+ (feePerVbyte >= swap.recommendedFee || feePerVbyte >= (yield this.config.feeEstimator.estimateFee()))) {
208
+ if (swap.state !== FromBtcTrustedSwap_1.FromBtcTrustedSwapState.RECEIVED)
209
+ return;
210
+ yield swap.setState(FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED);
211
+ yield this.storageManager.saveData(swap.getHash(), null, swap);
212
+ }
213
+ else {
214
+ return;
215
+ }
216
+ }
217
+ }
218
+ if (swap.doubleSpent || tx == null || foundVout == null || tx.id !== swap.txId) {
219
+ if (!swap.doubleSpent) {
220
+ swap.doubleSpent = true;
221
+ try {
222
+ yield this.burn(swap);
223
+ this.doubleSpendWatchdogSwaps.delete(swap);
224
+ }
225
+ catch (e) {
226
+ this.swapLogger.error(swap, "processPastSwap(): Error burning swap: ", e);
227
+ swap.doubleSpent = false;
228
+ }
229
+ }
230
+ return;
231
+ }
232
+ else {
233
+ if (!this.doubleSpendWatchdogSwaps.has(swap)) {
234
+ this.swapLogger.debug(swap, "processPastSwap(): Adding swap transaction to double spend watchdog list: ", swap.txId);
235
+ this.doubleSpendWatchdogSwaps.add(swap);
236
+ }
237
+ }
238
+ if (tx.confirmation_count > 0) {
239
+ this.swapLogger.debug(swap, "processPastSwap(): Removing confirmed swap transaction from double spend watchdog list: ", swap.txId);
240
+ this.doubleSpendWatchdogSwaps.delete(swap);
241
+ }
242
+ if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED) {
243
+ //Send gas token
244
+ const balance = swapContract.getBalance(signer.getAddress(), swapContract.getNativeCurrencyAddress(), false);
245
+ try {
246
+ yield this.checkBalance(swap.adjustedOutput, balance, null);
247
+ if (swap.metadata != null)
248
+ swap.metadata.times.receivedBalanceChecked = Date.now();
249
+ }
250
+ catch (e) {
251
+ this.swapLogger.error(swap, "processPastSwap(): Error not enough balance: ", e);
252
+ yield this.refundSwap(swap);
253
+ return;
254
+ }
255
+ if (swap.state !== FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED)
256
+ return;
257
+ let unlock = swap.lock(30 * 1000);
258
+ if (unlock == null)
259
+ return;
260
+ const txns = yield swapContract.txsTransfer(signer.getAddress(), swapContract.getNativeCurrencyAddress(), swap.adjustedOutput, swap.dstAddress);
261
+ yield swapContract.sendAndConfirm(signer, txns, true, null, false, (txId, rawTx) => __awaiter(this, void 0, void 0, function* () {
262
+ swap.txIds = { init: txId };
263
+ swap.scRawTx = rawTx;
264
+ if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED) {
265
+ yield swap.setState(FromBtcTrustedSwap_1.FromBtcTrustedSwapState.SENT);
266
+ yield this.storageManager.saveData(swap.getHash(), null, swap);
267
+ }
268
+ if (unlock != null)
269
+ unlock();
270
+ unlock = null;
271
+ }));
272
+ }
273
+ if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.SENT) {
274
+ const txStatus = yield swapContract.getTxStatus(swap.scRawTx);
275
+ switch (txStatus) {
276
+ case "not_found":
277
+ //Retry
278
+ swap.txIds = { init: null };
279
+ swap.scRawTx = null;
280
+ yield swap.setState(FromBtcTrustedSwap_1.FromBtcTrustedSwapState.RECEIVED);
281
+ yield this.storageManager.saveData(swap.getHash(), null, swap);
282
+ break;
283
+ case "reverted":
284
+ //Cancel invoice
285
+ yield this.refundSwap(swap);
286
+ this.swapLogger.info(swap, "processPastSwap(): transaction reverted, refunding btc on-chain: ", swap.btcAddress);
287
+ break;
288
+ case "success":
289
+ yield swap.setState(FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CONFIRMED);
290
+ yield this.storageManager.saveData(swap.getHash(), null, swap);
291
+ break;
292
+ }
293
+ }
294
+ if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CONFIRMED) {
295
+ this.processedTxIds.set(swap.getHash(), {
296
+ txId: swap.txIds.init,
297
+ adjustedAmount: swap.adjustedInput,
298
+ adjustedTotal: swap.adjustedOutput
299
+ });
300
+ if (tx.confirmation_count > 0)
301
+ yield this.removeSwapData(swap, FromBtcTrustedSwap_1.FromBtcTrustedSwapState.FINISHED);
302
+ }
303
+ });
304
+ }
305
+ processPastSwaps() {
306
+ return __awaiter(this, void 0, void 0, function* () {
307
+ const queriedData = yield this.storageManager.query([
308
+ {
309
+ key: "state",
310
+ value: [
311
+ FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CREATED,
312
+ FromBtcTrustedSwap_1.FromBtcTrustedSwapState.RECEIVED,
313
+ FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED,
314
+ FromBtcTrustedSwap_1.FromBtcTrustedSwapState.SENT,
315
+ FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CONFIRMED
316
+ ]
317
+ }
318
+ ]);
319
+ const startingBlockheight = queriedData.reduce((prev, swap) => Math.min(prev, swap.createdHeight), Infinity);
320
+ if (startingBlockheight === Infinity)
321
+ return;
322
+ const { transactions } = yield (0, lightning_1.getChainTransactions)({ lnd: this.LND, after: startingBlockheight });
323
+ for (let swap of queriedData) {
324
+ const tx = transactions.find(tx => tx.output_addresses.includes(swap.btcAddress));
325
+ yield this.processPastSwap(swap, tx);
326
+ }
327
+ });
328
+ }
329
+ isValidBitcoinAddress(address) {
330
+ try {
331
+ bitcoin.address.toOutputScript(address, this.config.bitcoinNetwork);
332
+ return true;
333
+ }
334
+ catch (e) { }
335
+ return false;
336
+ }
337
+ startRestServer(restServer) {
338
+ const getAddress = (0, Utils_1.expressHandlerWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
339
+ var _a;
340
+ const metadata = { request: {}, times: {} };
341
+ const chainIdentifier = (_a = req.query.chain) !== null && _a !== void 0 ? _a : this.chains.default;
342
+ const { swapContract, signer } = this.getChain(chainIdentifier);
343
+ metadata.times.requestReceived = Date.now();
344
+ /**
345
+ * address: string solana address of the recipient
346
+ * refundAddress: string bitcoin address to use in case of refund
347
+ * amount: string amount (in lamports/smart chain base units) of the invoice
348
+ * exactOut: boolean whether to create and exact output swap
349
+ */
350
+ const parsedBody = yield req.paramReader.getParams({
351
+ address: (val) => val != null &&
352
+ typeof (val) === "string" &&
353
+ swapContract.isValidAddress(val) ? val : null,
354
+ refundAddress: (val) => val != null &&
355
+ typeof (val) === "string" &&
356
+ this.isValidBitcoinAddress(val) ? val : null,
357
+ amount: SchemaVerifier_1.FieldTypeEnum.BN,
358
+ exactOut: SchemaVerifier_1.FieldTypeEnum.BooleanOptional
359
+ });
360
+ if (parsedBody == null)
361
+ throw {
362
+ code: 20100,
363
+ msg: "Invalid request body"
364
+ };
365
+ metadata.request = parsedBody;
366
+ const requestedAmount = { input: !parsedBody.exactOut, amount: parsedBody.amount };
367
+ const request = {
368
+ chainIdentifier,
369
+ raw: req,
370
+ parsed: parsedBody,
371
+ metadata
372
+ };
373
+ const useToken = swapContract.getNativeCurrencyAddress();
374
+ //Check request params
375
+ const fees = yield this.preCheckAmounts(request, requestedAmount, useToken);
376
+ metadata.times.requestChecked = Date.now();
377
+ //Create abortController for parallel prefetches
378
+ const responseStream = res.responseStream;
379
+ const abortController = this.getAbortController(responseStream);
380
+ //Pre-fetch data
381
+ const { pricePrefetchPromise } = this.getFromBtcPricePrefetches(chainIdentifier, useToken, abortController);
382
+ const balancePrefetch = swapContract.getBalance(signer.getAddress(), useToken, false).catch(e => {
383
+ this.logger.error("getBalancePrefetch(): balancePrefetch error: ", e);
384
+ abortController.abort(e);
385
+ return null;
386
+ });
387
+ //Check valid amount specified (min/max)
388
+ const { amountBD, swapFee, swapFeeInToken, totalInToken } = yield this.checkFromBtcAmount(request, requestedAmount, fees, useToken, abortController.signal, pricePrefetchPromise);
389
+ metadata.times.priceCalculated = Date.now();
390
+ //Check if we have enough funds to honor the request
391
+ yield this.checkBalance(totalInToken, balancePrefetch, abortController.signal);
392
+ metadata.times.balanceChecked = Date.now();
393
+ const { address: receiveAddress } = yield (0, lightning_1.createChainAddress)({
394
+ lnd: this.LND,
395
+ format: "p2wpkh"
396
+ });
397
+ abortController.signal.throwIfAborted();
398
+ metadata.times.addressCreated = Date.now();
399
+ const { current_block_height } = yield (0, lightning_1.getHeight)({ lnd: this.LND });
400
+ const feeRate = yield this.config.feeEstimator.estimateFee();
401
+ const recommendedFee = Math.ceil(feeRate * this.config.recommendFeeMultiplier);
402
+ const createdSwap = new FromBtcTrustedSwap_1.FromBtcTrustedSwap(chainIdentifier, swapFee, swapFeeInToken, receiveAddress, amountBD, parsedBody.address, totalInToken, current_block_height, Date.now() + (this.config.swapAddressExpiry * 1000), recommendedFee, parsedBody.refundAddress);
403
+ metadata.times.swapCreated = Date.now();
404
+ createdSwap.metadata = metadata;
405
+ yield PluginManager_1.PluginManager.swapCreate(createdSwap);
406
+ yield this.storageManager.saveData(createdSwap.getHash(), null, createdSwap);
407
+ this.subscriptions.set(createdSwap.btcAddress, createdSwap);
408
+ this.swapLogger.info(createdSwap, "REST: /getAddress: Created swap address: " + createdSwap.btcAddress + " amount: " + amountBD.toString(10));
409
+ yield responseStream.writeParamsAndEnd({
410
+ msg: "Success",
411
+ code: 10000,
412
+ data: {
413
+ paymentHash: createdSwap.getHash(),
414
+ btcAddress: receiveAddress,
415
+ amountSats: amountBD.toString(10),
416
+ swapFeeSats: swapFee.toString(10),
417
+ swapFee: swapFeeInToken.toString(10),
418
+ total: totalInToken.toString(10),
419
+ intermediaryKey: signer.getAddress(),
420
+ recommendedFee,
421
+ expiresAt: createdSwap.expiresAt
422
+ }
423
+ });
424
+ }));
425
+ restServer.use(this.path + "/getAddress", (0, ServerParamDecoder_1.serverParamDecoder)(10 * 1000));
426
+ restServer.post(this.path + "/getAddress", getAddress);
427
+ const getInvoiceStatus = (0, Utils_1.expressHandlerWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
428
+ /**
429
+ * paymentHash: string payment hash of the invoice
430
+ */
431
+ const parsedBody = (0, SchemaVerifier_1.verifySchema)(req.query, {
432
+ paymentHash: (val) => val != null &&
433
+ typeof (val) === "string" &&
434
+ val.length === 64 &&
435
+ Utils_1.HEX_REGEX.test(val) ? val : null,
436
+ });
437
+ const processedTxData = this.processedTxIds.get(parsedBody.paymentHash);
438
+ if (processedTxData != null)
439
+ throw {
440
+ _httpStatus: 200,
441
+ code: 10000,
442
+ msg: "Success, tx confirmed",
443
+ data: processedTxData
444
+ };
445
+ const refundTxId = this.refundedSwaps.get(parsedBody.paymentHash);
446
+ if (refundTxId != null)
447
+ throw {
448
+ _httpStatus: 200,
449
+ code: 10014,
450
+ msg: "Refunded",
451
+ data: {
452
+ txId: refundTxId
453
+ }
454
+ };
455
+ const doubleSpendTxId = this.doubleSpentSwaps.get(parsedBody.paymentHash);
456
+ if (doubleSpendTxId != null)
457
+ throw {
458
+ _httpStatus: 200,
459
+ code: 10015,
460
+ msg: "Double spend detected, deposit burned",
461
+ data: {
462
+ txId: doubleSpendTxId
463
+ }
464
+ };
465
+ const invoiceData = yield this.storageManager.getData(parsedBody.paymentHash, null);
466
+ if (invoiceData == null)
467
+ throw {
468
+ _httpStatus: 200,
469
+ code: 10001,
470
+ msg: "Swap expired/canceled"
471
+ };
472
+ if (invoiceData.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CREATED)
473
+ throw {
474
+ _httpStatus: 200,
475
+ code: 10010,
476
+ msg: "Bitcoin yet unpaid"
477
+ };
478
+ if (invoiceData.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.RECEIVED)
479
+ throw {
480
+ _httpStatus: 200,
481
+ code: 10011,
482
+ msg: "Bitcoin received, payment processing",
483
+ data: {
484
+ adjustedAmount: invoiceData.adjustedInput.toString(10),
485
+ adjustedTotal: invoiceData.adjustedOutput.toString(10)
486
+ }
487
+ };
488
+ if (invoiceData.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED)
489
+ throw {
490
+ _httpStatus: 200,
491
+ code: 10013,
492
+ msg: "Bitcoin accepted, payment processing",
493
+ data: {
494
+ adjustedAmount: invoiceData.adjustedInput.toString(10),
495
+ adjustedTotal: invoiceData.adjustedOutput.toString(10)
496
+ }
497
+ };
498
+ if (invoiceData.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.SENT)
499
+ throw {
500
+ _httpStatus: 200,
501
+ code: 10012,
502
+ msg: "Tx sent",
503
+ data: {
504
+ adjustedAmount: invoiceData.adjustedInput.toString(10),
505
+ adjustedTotal: invoiceData.adjustedOutput.toString(10),
506
+ txId: invoiceData.txIds.init
507
+ }
508
+ };
509
+ if (invoiceData.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CONFIRMED || invoiceData.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.FINISHED)
510
+ throw {
511
+ _httpStatus: 200,
512
+ code: 10000,
513
+ msg: "Success, tx confirmed",
514
+ data: {
515
+ adjustedAmount: invoiceData.adjustedInput.toString(10),
516
+ adjustedTotal: invoiceData.adjustedOutput.toString(10),
517
+ txId: invoiceData.txIds.init
518
+ }
519
+ };
520
+ }));
521
+ restServer.get(this.path + "/getAddressStatus", getInvoiceStatus);
522
+ this.logger.info("started at path: ", this.path);
523
+ }
524
+ checkDoubleSpends() {
525
+ return __awaiter(this, void 0, void 0, function* () {
526
+ for (let swap of this.doubleSpendWatchdogSwaps.keys()) {
527
+ const tx = yield this.bitcoinRpc.getTransaction(swap.txId);
528
+ if (tx == null) {
529
+ this.swapLogger.debug(swap, "checkDoubleSpends(): Swap was double spent, burning... - original txId: " + swap.txId);
530
+ this.processPastSwap(swap, null);
531
+ }
532
+ }
533
+ });
534
+ }
535
+ startDoubleSpendWatchdog() {
536
+ return __awaiter(this, void 0, void 0, function* () {
537
+ let rerun;
538
+ rerun = () => __awaiter(this, void 0, void 0, function* () {
539
+ yield this.checkDoubleSpends().catch(e => console.error(e));
540
+ setTimeout(rerun, this.config.doubleSpendCheckInterval);
541
+ });
542
+ yield rerun();
543
+ });
544
+ }
545
+ listenToTxns() {
546
+ const res = (0, lightning_1.subscribeToTransactions)({ lnd: this.LND });
547
+ res.on("chain_transaction", (tx) => {
548
+ for (let address of tx.output_addresses) {
549
+ const savedSwap = this.subscriptions.get(address);
550
+ if (savedSwap == null)
551
+ continue;
552
+ this.processPastSwap(savedSwap, tx);
553
+ return;
554
+ }
555
+ });
556
+ }
557
+ startWatchdog() {
558
+ const _super = Object.create(null, {
559
+ startWatchdog: { get: () => super.startWatchdog }
560
+ });
561
+ return __awaiter(this, void 0, void 0, function* () {
562
+ yield _super.startWatchdog.call(this);
563
+ yield this.startDoubleSpendWatchdog();
564
+ });
565
+ }
566
+ init() {
567
+ return __awaiter(this, void 0, void 0, function* () {
568
+ yield this.storageManager.loadData(FromBtcTrustedSwap_1.FromBtcTrustedSwap);
569
+ this.listenToTxns();
570
+ yield PluginManager_1.PluginManager.serviceInitialize(this);
571
+ });
572
+ }
573
+ getInfoData() {
574
+ return {};
575
+ }
576
+ processClaimEvent(chainIdentifier, event) {
577
+ return Promise.resolve(undefined);
578
+ }
579
+ processInitializeEvent(chainIdentifier, event) {
580
+ return Promise.resolve(undefined);
581
+ }
582
+ processRefundEvent(chainIdentifier, event) {
583
+ return Promise.resolve(undefined);
584
+ }
585
+ }
586
+ exports.FromBtcTrusted = FromBtcTrusted;
@@ -0,0 +1,43 @@
1
+ import { SwapData } from "@atomiqlabs/base";
2
+ import { FromBtcBaseSwap } from "../FromBtcBaseSwap";
3
+ import * as BN from "bn.js";
4
+ export declare enum FromBtcTrustedSwapState {
5
+ DOUBLE_SPENT = -3,
6
+ REFUNDED = -2,
7
+ EXPIRED = -1,
8
+ CREATED = 0,
9
+ RECEIVED = 1,
10
+ BTC_CONFIRMED = 2,
11
+ SENT = 3,
12
+ CONFIRMED = 4,
13
+ FINISHED = 5
14
+ }
15
+ export declare class FromBtcTrustedSwap<T extends SwapData = SwapData> extends FromBtcBaseSwap<T, FromBtcTrustedSwapState> {
16
+ readonly btcAddress: string;
17
+ readonly inputSats: BN;
18
+ readonly dstAddress: string;
19
+ readonly outputTokens: BN;
20
+ readonly createdHeight: number;
21
+ readonly expiresAt: number;
22
+ readonly recommendedFee: number;
23
+ readonly refundAddress: string;
24
+ adjustedInput: BN;
25
+ adjustedOutput: BN;
26
+ doubleSpent: boolean;
27
+ scRawTx: string;
28
+ rawTx: string;
29
+ txId: string;
30
+ vout: number;
31
+ burnTxId: string;
32
+ refundTxId: string;
33
+ constructor(chainIdentifier: string, swapFee: BN, swapFeeInToken: BN, btcAddress: string, inputSats: BN, dstAddress: string, outputTokens: BN, createdHeight: number, expiresAt: number, recommendedFee: number, refundAddress: string);
34
+ constructor(obj: any);
35
+ serialize(): any;
36
+ getHash(): string;
37
+ getSequence(): BN;
38
+ getOutputAmount(): BN;
39
+ getTotalInputAmount(): BN;
40
+ isFailed(): boolean;
41
+ isInitiated(): boolean;
42
+ isSuccess(): boolean;
43
+ }