@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.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/info/InfoHandler.js +0 -3
- package/dist/plugins/IPlugin.d.ts +2 -2
- package/dist/plugins/PluginManager.d.ts +2 -2
- package/dist/storagemanager/IntermediaryStorageManager.d.ts +1 -0
- package/dist/storagemanager/IntermediaryStorageManager.js +9 -2
- package/dist/storagemanager/StorageManager.d.ts +1 -0
- package/dist/storagemanager/StorageManager.js +9 -2
- package/dist/swaps/SwapHandler.d.ts +4 -10
- package/dist/swaps/SwapHandler.js +4 -13
- package/dist/swaps/assertions/FromBtcAmountAssertions.d.ts +2 -2
- package/dist/swaps/assertions/FromBtcAmountAssertions.js +13 -5
- package/dist/swaps/escrow/EscrowHandlerSwap.js +2 -2
- package/dist/swaps/escrow/FromBtcBaseSwapHandler.d.ts +2 -1
- package/dist/swaps/escrow/FromBtcBaseSwapHandler.js +8 -5
- package/dist/swaps/escrow/frombtc_abstract/FromBtcAbs.js +2 -2
- package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnAbs.js +11 -13
- package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +1 -0
- package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnSwapAbs.js +3 -0
- package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.d.ts +111 -0
- package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.js +682 -0
- package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAutoSwap.d.ts +55 -0
- package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAutoSwap.js +120 -0
- package/dist/swaps/escrow/tobtc_abstract/ToBtcAbs.d.ts +0 -2
- package/dist/swaps/escrow/tobtc_abstract/ToBtcAbs.js +44 -27
- package/dist/swaps/escrow/tobtcln_abstract/ToBtcLnAbs.js +12 -10
- package/dist/swaps/spv_vault_swap/SpvVault.d.ts +2 -3
- package/dist/swaps/spv_vault_swap/SpvVault.js +2 -2
- package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.js +10 -8
- package/dist/swaps/spv_vault_swap/SpvVaults.d.ts +4 -9
- package/dist/swaps/spv_vault_swap/SpvVaults.js +114 -80
- package/dist/swaps/trusted/frombtc_trusted/FromBtcTrusted.js +3 -3
- package/dist/swaps/trusted/frombtcln_trusted/FromBtcLnTrusted.js +14 -17
- package/dist/utils/Utils.d.ts +7 -7
- package/dist/utils/Utils.js +12 -11
- package/dist/utils/paramcoders/server/ServerParamDecoder.js +8 -6
- package/dist/wallets/IBitcoinWallet.d.ts +7 -0
- package/package.json +3 -3
- package/src/index.ts +2 -0
- package/src/info/InfoHandler.ts +0 -6
- package/src/plugins/IPlugin.ts +2 -2
- package/src/plugins/PluginManager.ts +2 -2
- package/src/storagemanager/IntermediaryStorageManager.ts +11 -2
- package/src/storagemanager/StorageManager.ts +12 -2
- package/src/swaps/SwapHandler.ts +6 -17
- package/src/swaps/assertions/FromBtcAmountAssertions.ts +16 -8
- package/src/swaps/escrow/EscrowHandlerSwap.ts +2 -2
- package/src/swaps/escrow/FromBtcBaseSwapHandler.ts +8 -5
- package/src/swaps/escrow/frombtc_abstract/FromBtcAbs.ts +2 -2
- package/src/swaps/escrow/frombtcln_abstract/FromBtcLnAbs.ts +11 -12
- package/src/swaps/escrow/frombtcln_abstract/FromBtcLnSwapAbs.ts +4 -0
- package/src/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.ts +847 -0
- package/src/swaps/escrow/frombtcln_autoinit/FromBtcLnAutoSwap.ts +196 -0
- package/src/swaps/escrow/tobtc_abstract/ToBtcAbs.ts +55 -36
- package/src/swaps/escrow/tobtcln_abstract/ToBtcLnAbs.ts +19 -15
- package/src/swaps/spv_vault_swap/SpvVault.ts +3 -3
- package/src/swaps/spv_vault_swap/SpvVaultSwapHandler.ts +10 -8
- package/src/swaps/spv_vault_swap/SpvVaults.ts +130 -91
- package/src/swaps/trusted/frombtc_trusted/FromBtcTrusted.ts +3 -3
- package/src/swaps/trusted/frombtcln_trusted/FromBtcLnTrusted.ts +13 -16
- package/src/utils/Utils.ts +19 -17
- package/src/utils/paramcoders/server/ServerParamDecoder.ts +9 -6
- package/src/wallets/IBitcoinWallet.ts +8 -0
- package/dist/wallets/ISpvVaultWallet.d.ts +0 -42
- 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,
|
|
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.
|
|
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.
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
317
|
+
if (vault.scOpenTxs != null) {
|
|
299
318
|
//Check if confirmed
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
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.
|
|
343
|
+
vault.scOpenTxs = { [txId]: rawTx };
|
|
316
344
|
await this.saveVault(vault);
|
|
317
345
|
}
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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.
|
|
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.
|
|
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 =>
|
|
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
|
|
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 =>
|
|
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 =>
|
|
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
|
-
|
|
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 =>
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
|
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;
|
package/dist/utils/Utils.d.ts
CHANGED
|
@@ -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;
|
package/dist/utils/Utils.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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": "
|
|
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": "^
|
|
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
|
|
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";
|
package/src/info/InfoHandler.ts
CHANGED
|
@@ -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
|
|
package/src/plugins/IPlugin.ts
CHANGED
|
@@ -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,
|