@atomiqlabs/lp-lib 12.1.0 → 13.0.0-beta.1

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 (119) hide show
  1. package/dist/index.d.ts +18 -13
  2. package/dist/index.js +18 -13
  3. package/dist/plugins/IPlugin.d.ts +35 -12
  4. package/dist/plugins/PluginManager.d.ts +38 -15
  5. package/dist/plugins/PluginManager.js +33 -9
  6. package/dist/prices/BinanceSwapPrice.d.ts +1 -1
  7. package/dist/prices/BinanceSwapPrice.js +1 -1
  8. package/dist/prices/CoinGeckoSwapPrice.d.ts +1 -1
  9. package/dist/prices/CoinGeckoSwapPrice.js +1 -1
  10. package/dist/{swaps → prices}/ISwapPrice.js +4 -0
  11. package/dist/prices/OKXSwapPrice.d.ts +1 -1
  12. package/dist/prices/OKXSwapPrice.js +1 -1
  13. package/dist/swaps/SwapHandler.d.ts +20 -58
  14. package/dist/swaps/SwapHandler.js +17 -186
  15. package/dist/swaps/SwapHandlerSwap.d.ts +8 -23
  16. package/dist/swaps/SwapHandlerSwap.js +7 -39
  17. package/dist/swaps/assertions/AmountAssertions.d.ts +28 -0
  18. package/dist/swaps/assertions/AmountAssertions.js +72 -0
  19. package/dist/swaps/assertions/FromBtcAmountAssertions.d.ts +76 -0
  20. package/dist/swaps/assertions/FromBtcAmountAssertions.js +162 -0
  21. package/dist/swaps/assertions/LightningAssertions.d.ts +44 -0
  22. package/dist/swaps/assertions/LightningAssertions.js +86 -0
  23. package/dist/swaps/assertions/ToBtcAmountAssertions.d.ts +53 -0
  24. package/dist/swaps/{ToBtcBaseSwapHandler.js → assertions/ToBtcAmountAssertions.js} +20 -94
  25. package/dist/swaps/escrow/EscrowHandler.d.ts +51 -0
  26. package/dist/swaps/escrow/EscrowHandler.js +158 -0
  27. package/dist/swaps/escrow/EscrowHandlerSwap.d.ts +35 -0
  28. package/dist/swaps/escrow/EscrowHandlerSwap.js +69 -0
  29. package/dist/swaps/{FromBtcBaseSwap.d.ts → escrow/FromBtcBaseSwap.d.ts} +2 -3
  30. package/dist/swaps/{FromBtcBaseSwap.js → escrow/FromBtcBaseSwap.js} +4 -7
  31. package/dist/swaps/{FromBtcBaseSwapHandler.d.ts → escrow/FromBtcBaseSwapHandler.d.ts} +10 -49
  32. package/dist/swaps/{FromBtcBaseSwapHandler.js → escrow/FromBtcBaseSwapHandler.js} +16 -137
  33. package/dist/swaps/{ToBtcBaseSwap.d.ts → escrow/ToBtcBaseSwap.d.ts} +2 -2
  34. package/dist/swaps/{ToBtcBaseSwap.js → escrow/ToBtcBaseSwap.js} +4 -4
  35. package/dist/swaps/escrow/ToBtcBaseSwapHandler.d.ts +53 -0
  36. package/dist/swaps/escrow/ToBtcBaseSwapHandler.js +81 -0
  37. package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.d.ts +4 -4
  38. package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.js +15 -15
  39. package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.js +1 -1
  40. package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.d.ts +9 -7
  41. package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.js +22 -19
  42. package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.js +3 -3
  43. package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.d.ts +4 -4
  44. package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.js +14 -13
  45. package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.js +3 -3
  46. package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.d.ts +6 -26
  47. package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.js +20 -57
  48. package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.js +3 -3
  49. package/dist/swaps/spv_vault_swap/SpvVault.d.ts +41 -0
  50. package/dist/swaps/spv_vault_swap/SpvVault.js +111 -0
  51. package/dist/swaps/spv_vault_swap/SpvVaultSwap.d.ts +63 -0
  52. package/dist/swaps/spv_vault_swap/SpvVaultSwap.js +145 -0
  53. package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.d.ts +68 -0
  54. package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.js +469 -0
  55. package/dist/swaps/spv_vault_swap/SpvVaults.d.ts +57 -0
  56. package/dist/swaps/spv_vault_swap/SpvVaults.js +369 -0
  57. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.d.ts +10 -13
  58. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.js +25 -30
  59. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.d.ts +9 -4
  60. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.js +15 -7
  61. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.d.ts +12 -14
  62. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.js +33 -35
  63. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.d.ts +9 -4
  64. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.js +17 -7
  65. package/dist/utils/Utils.d.ts +13 -5
  66. package/dist/utils/Utils.js +23 -1
  67. package/dist/wallets/IBitcoinWallet.d.ts +6 -0
  68. package/dist/wallets/ISpvVaultSigner.d.ts +7 -0
  69. package/dist/wallets/ISpvVaultSigner.js +2 -0
  70. package/dist/wallets/ISpvVaultWallet.d.ts +42 -0
  71. package/dist/wallets/ISpvVaultWallet.js +2 -0
  72. package/package.json +2 -2
  73. package/src/index.ts +21 -15
  74. package/src/plugins/IPlugin.ts +27 -19
  75. package/src/plugins/PluginManager.ts +51 -26
  76. package/src/prices/BinanceSwapPrice.ts +1 -1
  77. package/src/prices/CoinGeckoSwapPrice.ts +1 -1
  78. package/src/{swaps → prices}/ISwapPrice.ts +4 -0
  79. package/src/prices/OKXSwapPrice.ts +1 -1
  80. package/src/swaps/SwapHandler.ts +22 -205
  81. package/src/swaps/SwapHandlerSwap.ts +10 -46
  82. package/src/swaps/assertions/AmountAssertions.ts +77 -0
  83. package/src/swaps/assertions/FromBtcAmountAssertions.ts +228 -0
  84. package/src/swaps/assertions/LightningAssertions.ts +103 -0
  85. package/src/swaps/{ToBtcBaseSwapHandler.ts → assertions/ToBtcAmountAssertions.ts} +27 -142
  86. package/src/swaps/escrow/EscrowHandler.ts +179 -0
  87. package/src/swaps/escrow/EscrowHandlerSwap.ts +87 -0
  88. package/src/swaps/{FromBtcBaseSwap.ts → escrow/FromBtcBaseSwap.ts} +4 -8
  89. package/src/swaps/{FromBtcBaseSwapHandler.ts → escrow/FromBtcBaseSwapHandler.ts} +30 -190
  90. package/src/swaps/{ToBtcBaseSwap.ts → escrow/ToBtcBaseSwap.ts} +4 -5
  91. package/src/swaps/escrow/ToBtcBaseSwapHandler.ts +130 -0
  92. package/src/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.ts +20 -20
  93. package/src/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.ts +1 -1
  94. package/src/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.ts +29 -25
  95. package/src/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.ts +2 -2
  96. package/src/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.ts +19 -18
  97. package/src/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.ts +2 -2
  98. package/src/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.ts +26 -66
  99. package/src/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.ts +2 -2
  100. package/src/swaps/spv_vault_swap/SpvVault.ts +143 -0
  101. package/src/swaps/spv_vault_swap/SpvVaultSwap.ts +207 -0
  102. package/src/swaps/spv_vault_swap/SpvVaultSwapHandler.ts +606 -0
  103. package/src/swaps/spv_vault_swap/SpvVaults.ts +441 -0
  104. package/src/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.ts +36 -51
  105. package/src/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.ts +18 -8
  106. package/src/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.ts +43 -52
  107. package/src/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.ts +20 -8
  108. package/src/utils/Utils.ts +27 -1
  109. package/src/wallets/IBitcoinWallet.ts +4 -0
  110. package/src/wallets/ISpvVaultSigner.ts +11 -0
  111. package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +0 -26
  112. package/dist/swaps/FromBtcLnBaseSwapHandler.js +0 -46
  113. package/dist/swaps/ToBtcBaseSwapHandler.d.ts +0 -95
  114. package/src/swaps/FromBtcLnBaseSwapHandler.ts +0 -63
  115. /package/dist/{swaps → prices}/ISwapPrice.d.ts +0 -0
  116. /package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.d.ts +0 -0
  117. /package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.d.ts +0 -0
  118. /package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.d.ts +0 -0
  119. /package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.d.ts +0 -0
@@ -0,0 +1,369 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SpvVaults = exports.VAULT_DUST_AMOUNT = void 0;
4
+ const SpvVault_1 = require("./SpvVault");
5
+ const Utils_1 = require("../../utils/Utils");
6
+ const PluginManager_1 = require("../../plugins/PluginManager");
7
+ const AmountAssertions_1 = require("../assertions/AmountAssertions");
8
+ const btc_signer_1 = require("@scure/btc-signer");
9
+ exports.VAULT_DUST_AMOUNT = 600;
10
+ const VAULT_INIT_CONFIRMATIONS = 2;
11
+ const BTC_FINALIZATION_CONFIRMATIONS = 6;
12
+ class SpvVaults {
13
+ constructor(vaultStorage, bitcoin, vaultSigner, bitcoinRpc, getChain, config) {
14
+ this.logger = {
15
+ debug: (msg, ...args) => console.debug("SpvVaults: " + msg, ...args),
16
+ info: (msg, ...args) => console.info("SpvVaults: " + msg, ...args),
17
+ warn: (msg, ...args) => console.warn("SpvVaults: " + msg, ...args),
18
+ error: (msg, ...args) => console.error("SpvVaults: " + msg, ...args)
19
+ };
20
+ this.vaultStorage = vaultStorage;
21
+ this.bitcoin = bitcoin;
22
+ this.vaultSigner = vaultSigner;
23
+ this.bitcoinRpc = bitcoinRpc;
24
+ this.getChain = getChain;
25
+ this.config = config;
26
+ }
27
+ async processDepositEvent(vault, event) {
28
+ vault.update(event);
29
+ await this.saveVault(vault);
30
+ }
31
+ async processOpenEvent(vault, event) {
32
+ if (vault.state === SpvVault_1.SpvVaultState.BTC_CONFIRMED) {
33
+ vault.state = SpvVault_1.SpvVaultState.OPENED;
34
+ }
35
+ vault.update(event);
36
+ await this.saveVault(vault);
37
+ }
38
+ async processCloseEvent(vault, event) {
39
+ if (vault.state === SpvVault_1.SpvVaultState.OPENED) {
40
+ vault.state = SpvVault_1.SpvVaultState.CLOSED;
41
+ }
42
+ vault.update(event);
43
+ await this.saveVault(vault);
44
+ }
45
+ async processClaimEvent(vault, swap, event) {
46
+ //Update vault
47
+ const foundPendingWithdrawal = vault.pendingWithdrawals.findIndex(val => val.btcTx.txid === event.btcTxId);
48
+ if (foundPendingWithdrawal !== -1)
49
+ vault.pendingWithdrawals.splice(foundPendingWithdrawal, 1);
50
+ vault.update(event);
51
+ await this.saveVault(vault);
52
+ }
53
+ async createVaults(chainId, count, token, confirmations = 2, feeRate) {
54
+ const { signer, chainInterface, tokenMultipliers, spvVaultContract } = this.getChain(chainId);
55
+ const signerAddress = signer.getAddress();
56
+ //Check vaultId of the latest saved vault
57
+ let latestVaultId = -1n;
58
+ for (let key in this.vaultStorage.data) {
59
+ const vault = this.vaultStorage.data[key];
60
+ if (vault.chainId !== chainId)
61
+ continue;
62
+ if (vault.data.getOwner() !== signerAddress)
63
+ continue;
64
+ if (vault.data.getVaultId() > latestVaultId)
65
+ latestVaultId = vault.data.getVaultId();
66
+ }
67
+ latestVaultId++;
68
+ const vaultAddreses = [];
69
+ for (let i = 0; i < count; i++) {
70
+ const vaultId = latestVaultId + BigInt(i);
71
+ const address = await this.vaultSigner.getAddress(chainId, vaultId);
72
+ vaultAddreses.push({ vaultId, address });
73
+ }
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
+ const nativeToken = chainInterface.getNativeCurrencyAddress();
79
+ const vaults = await Promise.all(vaultAddreses.map(async (val, index) => {
80
+ const vaultData = await spvVaultContract.createVaultData(signerAddress, val.vaultId, txResult.txId + ":" + index, confirmations, [
81
+ { token, multiplier: tokenMultipliers?.[token] ?? 1n },
82
+ { token: nativeToken, multiplier: tokenMultipliers?.[nativeToken] ?? 1n }
83
+ ]);
84
+ return new SpvVault_1.SpvVault(chainId, vaultData, val.address);
85
+ }));
86
+ //Save vaults
87
+ if (this.vaultStorage.saveDataArr != null) {
88
+ await this.vaultStorage.saveDataArr(vaults.map(val => {
89
+ return { id: val.getIdentifier(), object: val };
90
+ }));
91
+ }
92
+ else {
93
+ for (let vault of vaults) {
94
+ await this.vaultStorage.saveData(vault.getIdentifier(), vault);
95
+ }
96
+ }
97
+ //Send bitcoin tx
98
+ await this.bitcoin.sendRawTransaction(txResult.raw);
99
+ this.logger.info("createVaults(): Funding " + count + " vaults, bitcoin txId: " + txResult.txId);
100
+ return {
101
+ vaultsCreated: vaults.map(val => val.data.getVaultId()),
102
+ btcTxId: txResult.txId
103
+ };
104
+ }
105
+ async listVaults(chainId, token) {
106
+ return Object.keys(this.vaultStorage.data)
107
+ .map(key => this.vaultStorage.data[key])
108
+ .filter(val => chainId == null ? true : val.chainId === chainId)
109
+ .filter(val => val.data.getOwner() === this.getChain(val.chainId)?.signer?.getAddress())
110
+ .filter(val => token == null ? true : val.data.getTokenData()[0].token === token);
111
+ }
112
+ async fundVault(vault, tokenAmounts) {
113
+ if (vault.state !== SpvVault_1.SpvVaultState.OPENED)
114
+ throw new Error("Vault not opened!");
115
+ this.logger.info("fundVault(): Depositing tokens to the vault " + vault.data.getVaultId().toString(10) + ", amounts: " + tokenAmounts.map(val => val.toString(10)).join(", "));
116
+ const { signer, spvVaultContract } = this.getChain(vault.chainId);
117
+ const txId = await spvVaultContract.deposit(signer, vault.data, tokenAmounts, { waitForConfirmation: true });
118
+ this.logger.info("fundVault(): Tokens deposited to vault " + vault.data.getVaultId().toString(10) + ", amounts: " + tokenAmounts.map(val => val.toString(10)).join(", ") + ", txId: " + txId);
119
+ return txId;
120
+ }
121
+ async withdrawFromVault(vault, tokenAmounts, feeRate) {
122
+ tokenAmounts.forEach((rawAmount, index) => {
123
+ if (vault.balances[index] == null)
124
+ throw new Error("Token not found in the vault");
125
+ if (vault.balances[index].rawAmount < rawAmount)
126
+ throw new Error("Not enough balance in the vault");
127
+ });
128
+ if (!vault.isReady())
129
+ throw new Error("Vault not ready, wait for the latest swap to get at least 1 confirmation!");
130
+ const { signer, spvVaultContract } = this.getChain(vault.chainId);
131
+ const latestUtxo = vault.getLatestUtxo();
132
+ const [txId, voutStr] = latestUtxo.split(":");
133
+ const opReturnData = spvVaultContract.toOpReturnData(signer.getAddress(), tokenAmounts);
134
+ let opReturnScript;
135
+ if (opReturnData.length < 76) {
136
+ opReturnScript = Buffer.concat([
137
+ Buffer.from([0x6a, opReturnData.length]),
138
+ opReturnData
139
+ ]);
140
+ }
141
+ else {
142
+ opReturnScript = Buffer.concat([
143
+ Buffer.from([0x6a, 0x4c, opReturnData.length]),
144
+ opReturnData
145
+ ]);
146
+ }
147
+ let psbt = new btc_signer_1.Transaction({
148
+ allowUnknownOutputs: true
149
+ });
150
+ psbt.addInput({
151
+ txid: txId,
152
+ index: parseInt(voutStr),
153
+ witnessUtxo: {
154
+ amount: BigInt(exports.VAULT_DUST_AMOUNT),
155
+ script: this.bitcoin.toOutputScript(vault.btcAddress)
156
+ }
157
+ });
158
+ psbt.addOutput({
159
+ amount: BigInt(exports.VAULT_DUST_AMOUNT),
160
+ script: this.bitcoin.toOutputScript(vault.btcAddress)
161
+ });
162
+ psbt.addOutput({
163
+ amount: 0n,
164
+ script: opReturnScript
165
+ });
166
+ psbt = await this.bitcoin.fundPsbt(psbt, feeRate);
167
+ if (psbt.inputsLength < 2)
168
+ throw new Error("PSBT needs at least 2 inputs!");
169
+ psbt.updateInput(0, { sequence: 0x80000000 });
170
+ psbt.updateInput(1, { sequence: 0x80000000 });
171
+ psbt = await this.vaultSigner.signPsbt(vault.chainId, vault.data.getVaultId(), psbt, [0]);
172
+ const res = await this.bitcoin.signPsbt(psbt);
173
+ const parsedTransaction = await this.bitcoinRpc.parseTransaction(res.raw);
174
+ const withdrawalData = await spvVaultContract.getWithdrawalData(parsedTransaction);
175
+ if (withdrawalData.getSpentVaultUtxo() !== vault.getLatestUtxo()) {
176
+ throw new Error("Latest vault UTXO already spent! Please try again later.");
177
+ }
178
+ vault.addWithdrawal(withdrawalData);
179
+ await this.saveVault(vault);
180
+ try {
181
+ await this.bitcoin.sendRawTransaction(res.raw);
182
+ }
183
+ catch (e) {
184
+ vault.removeWithdrawal(withdrawalData);
185
+ await this.saveVault(vault);
186
+ throw e;
187
+ }
188
+ return res.txId;
189
+ }
190
+ async checkVaults() {
191
+ const vaults = Object.keys(this.vaultStorage.data).map(key => this.vaultStorage.data[key]);
192
+ const claimWithdrawals = [];
193
+ for (let vault of vaults) {
194
+ const { signer, spvVaultContract, chainInterface } = this.getChain(vault.chainId);
195
+ if (vault.data.getOwner() !== signer.getAddress())
196
+ continue;
197
+ if (vault.state === SpvVault_1.SpvVaultState.BTC_INITIATED) {
198
+ //Check if btc tx confirmed
199
+ const txId = vault.initialUtxo.split(":")[0];
200
+ const btcTx = await this.bitcoinRpc.getTransaction(txId);
201
+ if (btcTx.confirmations >= VAULT_INIT_CONFIRMATIONS) {
202
+ //Double-check the state here to prevent race condition
203
+ if (vault.state === SpvVault_1.SpvVaultState.BTC_INITIATED) {
204
+ vault.state = SpvVault_1.SpvVaultState.BTC_CONFIRMED;
205
+ await this.saveVault(vault);
206
+ }
207
+ this.logger.info("checkVaults(): Vault ID " + vault.data.getVaultId().toString(10) + " confirmed on bitcoin, opening vault on " + vault.chainId);
208
+ }
209
+ }
210
+ if (vault.state === SpvVault_1.SpvVaultState.BTC_CONFIRMED) {
211
+ //Check if open txs were sent already
212
+ if (vault.scOpenTx != null) {
213
+ //Check if confirmed
214
+ const status = await chainInterface.getTxStatus(vault.scOpenTx.rawTx);
215
+ if (status === "pending")
216
+ return;
217
+ if (status === "success") {
218
+ vault.state = SpvVault_1.SpvVaultState.OPENED;
219
+ await this.saveVault(vault);
220
+ return;
221
+ }
222
+ }
223
+ const txs = await spvVaultContract.txsOpen(signer.getAddress(), vault.data);
224
+ let numTx = 0;
225
+ const txIds = await chainInterface.sendAndConfirm(signer, txs, true, undefined, false, async (txId, rawTx) => {
226
+ numTx++;
227
+ if (numTx === txs.length) {
228
+ //Final tx
229
+ vault.scOpenTx = { txId, rawTx };
230
+ await this.saveVault(vault);
231
+ }
232
+ });
233
+ this.logger.info("checkVaults(): Vault ID " + vault.data.getVaultId().toString(10) + " opened on " + vault.chainId + " txId: " + txIds.join(", "));
234
+ vault.state = SpvVault_1.SpvVaultState.OPENED;
235
+ await this.saveVault(vault);
236
+ }
237
+ if (vault.state === SpvVault_1.SpvVaultState.OPENED) {
238
+ let changed = false;
239
+ //Check if some of the pendingWithdrawals got confirmed
240
+ let latestOwnWithdrawalIndex = -1;
241
+ let latestConfirmedWithdrawalIndex = -1;
242
+ for (let i = 0; i < vault.pendingWithdrawals.length; i++) {
243
+ const pendingWithdrawal = vault.pendingWithdrawals[i];
244
+ //Check all the pending withdrawals that were not finalized yet
245
+ if (pendingWithdrawal.btcTx.confirmations == null || pendingWithdrawal.btcTx.confirmations < BTC_FINALIZATION_CONFIRMATIONS) {
246
+ const btcTx = await this.bitcoinRpc.getTransaction(pendingWithdrawal.btcTx.txid);
247
+ if (btcTx == null) {
248
+ //Probable double-spend, remove from pending withdrawals
249
+ const index = vault.pendingWithdrawals.indexOf(pendingWithdrawal);
250
+ if (index === -1) {
251
+ this.logger.warn("checkVaults(): Tried to remove pending withdrawal txId: " + pendingWithdrawal.btcTx.txid + ", but doesn't exist anymore!");
252
+ }
253
+ else {
254
+ vault.pendingWithdrawals.splice(index, 1);
255
+ }
256
+ changed = true;
257
+ }
258
+ else {
259
+ //Update confirmations count
260
+ if (pendingWithdrawal.btcTx.confirmations !== btcTx.confirmations ||
261
+ pendingWithdrawal.btcTx.blockhash !== btcTx.blockhash) {
262
+ pendingWithdrawal.btcTx.confirmations = btcTx.confirmations;
263
+ pendingWithdrawal.btcTx.blockhash = btcTx.blockhash;
264
+ changed = true;
265
+ }
266
+ }
267
+ }
268
+ //Check it has enough confirmations
269
+ if (pendingWithdrawal.btcTx.confirmations >= vault.data.getConfirmations()) {
270
+ latestConfirmedWithdrawalIndex = i;
271
+ //Check if the pending withdrawals contain a withdrawal to our own address
272
+ if (pendingWithdrawal.isRecipient(signer.getAddress())) {
273
+ latestOwnWithdrawalIndex = i;
274
+ }
275
+ }
276
+ }
277
+ if (changed) {
278
+ await this.saveVault(vault);
279
+ }
280
+ if (this.config.maxUnclaimedWithdrawals != null && latestConfirmedWithdrawalIndex + 1 >= this.config.maxUnclaimedWithdrawals) {
281
+ this.logger.info("checkVaults(): Processing withdrawals by self, because a lot of them are unclaimed!");
282
+ claimWithdrawals.push({ vault, withdrawals: vault.pendingWithdrawals.slice(0, latestConfirmedWithdrawalIndex + 1) });
283
+ }
284
+ else if (latestOwnWithdrawalIndex !== -1) {
285
+ claimWithdrawals.push({ vault, withdrawals: vault.pendingWithdrawals.slice(0, latestOwnWithdrawalIndex + 1) });
286
+ }
287
+ }
288
+ }
289
+ for (let { vault, withdrawals } of claimWithdrawals) {
290
+ if (!await this.claimWithdrawals(vault, withdrawals)) {
291
+ this.logger.error("checkVaults(): Cannot process withdrawals " + withdrawals.map(val => val.btcTx.txid).join(", ") + " for vault: " + vault.data.getVaultId());
292
+ break;
293
+ }
294
+ }
295
+ }
296
+ async claimWithdrawals(vault, withdrawal) {
297
+ const { signer, spvVaultContract } = this.getChain(vault.chainId);
298
+ try {
299
+ const txId = await spvVaultContract.claim(signer, vault.data, withdrawal.map(tx => {
300
+ return { tx };
301
+ }), undefined, true, { waitForConfirmation: true });
302
+ this.logger.info("claimWithdrawal(): Successfully claimed withdrawals, btcTxIds: " + withdrawal.map(val => val.btcTx.txid).join(", ") + " smartChainTxId: " + txId);
303
+ return true;
304
+ }
305
+ catch (e) {
306
+ this.logger.error("claimWithdrawal(): Tried to claim but got error: ", e);
307
+ return false;
308
+ }
309
+ }
310
+ async getVault(chainId, owner, vaultId) {
311
+ return this.vaultStorage.data[chainId + "_" + owner + "_" + vaultId.toString(10)];
312
+ }
313
+ /**
314
+ * Returns a ready-to-use vault for a specific request
315
+ *
316
+ * @param chainIdentifier
317
+ * @param totalSats
318
+ * @param token
319
+ * @param amount
320
+ * @param gasToken
321
+ * @param gasTokenAmount
322
+ * @protected
323
+ */
324
+ async findVaultForSwap(chainIdentifier, totalSats, token, amount, gasToken, gasTokenAmount) {
325
+ const { signer } = this.getChain(chainIdentifier);
326
+ const pluginResponse = await PluginManager_1.PluginManager.onVaultSelection(chainIdentifier, totalSats, { token, amount }, { token: gasToken, amount: gasTokenAmount });
327
+ if (pluginResponse != null) {
328
+ AmountAssertions_1.AmountAssertions.handlePluginErrorResponses(pluginResponse);
329
+ return pluginResponse;
330
+ }
331
+ const candidates = Object.keys(this.vaultStorage.data)
332
+ .map(key => this.vaultStorage.data[key])
333
+ .filter(vault => vault.chainId === chainIdentifier && vault.data.getOwner() === signer.getAddress() && vault.isReady())
334
+ .filter(vault => {
335
+ const token0 = vault.balances[0];
336
+ if (token0.token !== token || token0.scaledAmount < amount)
337
+ return false;
338
+ if (gasToken != null && gasTokenAmount !== 0n) {
339
+ const token1 = vault.balances[1];
340
+ if (token1.token !== gasToken || token1.scaledAmount < gasTokenAmount)
341
+ return false;
342
+ }
343
+ return true;
344
+ });
345
+ candidates.sort((a, b) => (0, Utils_1.bigIntSorter)(a.balances[0].scaledAmount, b.balances[0].scaledAmount));
346
+ const result = candidates[0];
347
+ if (result == null)
348
+ throw {
349
+ code: 20301,
350
+ msg: "No suitable swap vault found, try again later!"
351
+ };
352
+ return result;
353
+ }
354
+ saveVault(vault) {
355
+ return this.vaultStorage.saveData(vault.getIdentifier(), vault);
356
+ }
357
+ async startVaultsWatchdog() {
358
+ let rerun;
359
+ rerun = async () => {
360
+ await this.checkVaults().catch(e => console.error(e));
361
+ setTimeout(rerun, this.config.vaultsCheckInterval);
362
+ };
363
+ await rerun();
364
+ }
365
+ async init() {
366
+ const vaults = await this.vaultStorage.loadData(SpvVault_1.SpvVault);
367
+ }
368
+ }
369
+ exports.SpvVaults = SpvVaults;
@@ -1,12 +1,12 @@
1
- import { FromBtcBaseConfig, FromBtcBaseSwapHandler } from "../FromBtcBaseSwapHandler";
2
1
  import { FromBtcTrustedSwap, FromBtcTrustedSwapState } from "./FromBtcTrustedSwap";
3
- import { BitcoinRpc, BtcBlock, BtcTx, ClaimEvent, InitializeEvent, RefundEvent, SwapData } from "@atomiqlabs/base";
2
+ import { BitcoinRpc, BtcBlock, BtcTx } from "@atomiqlabs/base";
4
3
  import { Express } from "express";
5
- import { MultichainData, SwapHandlerType } from "../SwapHandler";
6
- import { IIntermediaryStorage } from "../../storage/IIntermediaryStorage";
7
- import { ISwapPrice } from "../ISwapPrice";
8
- import { IBitcoinWallet } from "../../wallets/IBitcoinWallet";
9
- export type FromBtcTrustedConfig = FromBtcBaseConfig & {
4
+ import { MultichainData, SwapBaseConfig, SwapHandler, SwapHandlerType } from "../../SwapHandler";
5
+ import { IIntermediaryStorage } from "../../../storage/IIntermediaryStorage";
6
+ import { ISwapPrice } from "../../../prices/ISwapPrice";
7
+ import { IBitcoinWallet } from "../../../wallets/IBitcoinWallet";
8
+ import { FromBtcAmountAssertions } from "../../assertions/FromBtcAmountAssertions";
9
+ export type FromBtcTrustedConfig = SwapBaseConfig & {
10
10
  doubleSpendCheckInterval: number;
11
11
  swapAddressExpiry: number;
12
12
  recommendFeeMultiplier?: number;
@@ -18,9 +18,8 @@ export type FromBtcTrustedRequestType = {
18
18
  refundAddress?: string;
19
19
  token?: string;
20
20
  };
21
- export declare class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, FromBtcTrustedSwapState> {
22
- readonly type: SwapHandlerType;
23
- readonly swapType: any;
21
+ export declare class FromBtcTrusted extends SwapHandler<FromBtcTrustedSwap, FromBtcTrustedSwapState> {
22
+ readonly type = SwapHandlerType.FROM_BTC_TRUSTED;
24
23
  readonly config: FromBtcTrustedConfig;
25
24
  readonly bitcoin: IBitcoinWallet;
26
25
  readonly bitcoinRpc: BitcoinRpc<BtcBlock>;
@@ -34,6 +33,7 @@ export declare class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTruste
34
33
  adjustedAmount: bigint;
35
34
  adjustedTotal: bigint;
36
35
  }>;
36
+ readonly AmountAssertions: FromBtcAmountAssertions;
37
37
  constructor(storageDirectory: IIntermediaryStorage<FromBtcTrustedSwap>, path: string, chains: MultichainData, bitcoin: IBitcoinWallet, swapPricing: ISwapPrice, bitcoinRpc: BitcoinRpc<BtcBlock>, config: FromBtcTrustedConfig);
38
38
  private getAllAncestors;
39
39
  private refundSwap;
@@ -48,7 +48,4 @@ export declare class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTruste
48
48
  startWatchdog(): Promise<void>;
49
49
  init(): Promise<void>;
50
50
  getInfoData(): any;
51
- protected processClaimEvent(chainIdentifier: string, swap: FromBtcTrustedSwap, event: ClaimEvent<SwapData>): Promise<void>;
52
- protected processInitializeEvent(chainIdentifier: string, swap: FromBtcTrustedSwap, event: InitializeEvent<SwapData>): Promise<void>;
53
- protected processRefundEvent(chainIdentifier: string, swap: FromBtcTrustedSwap, event: RefundEvent<SwapData>): Promise<void>;
54
51
  }
@@ -1,23 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FromBtcTrusted = void 0;
4
- const FromBtcBaseSwapHandler_1 = require("../FromBtcBaseSwapHandler");
5
4
  const FromBtcTrustedSwap_1 = require("./FromBtcTrustedSwap");
6
- const SwapHandler_1 = require("../SwapHandler");
7
- const PluginManager_1 = require("../../plugins/PluginManager");
8
- const Utils_1 = require("../../utils/Utils");
9
- const SchemaVerifier_1 = require("../../utils/paramcoders/SchemaVerifier");
10
- class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
5
+ const SwapHandler_1 = require("../../SwapHandler");
6
+ const PluginManager_1 = require("../../../plugins/PluginManager");
7
+ const Utils_1 = require("../../../utils/Utils");
8
+ const SchemaVerifier_1 = require("../../../utils/paramcoders/SchemaVerifier");
9
+ const FromBtcAmountAssertions_1 = require("../../assertions/FromBtcAmountAssertions");
10
+ class FromBtcTrusted extends SwapHandler_1.SwapHandler {
11
11
  constructor(storageDirectory, path, chains, bitcoin, swapPricing, bitcoinRpc, config) {
12
12
  var _a;
13
13
  super(storageDirectory, path, chains, swapPricing);
14
14
  this.type = SwapHandler_1.SwapHandlerType.FROM_BTC_TRUSTED;
15
- this.swapType = null;
16
15
  this.subscriptions = new Map();
17
16
  this.doubleSpendWatchdogSwaps = new Set();
18
17
  this.refundedSwaps = new Map();
19
18
  this.doubleSpentSwaps = new Map();
20
19
  this.processedTxIds = new Map();
20
+ this.AmountAssertions = new FromBtcAmountAssertions_1.FromBtcAmountAssertions(config, swapPricing);
21
21
  this.config = config;
22
22
  (_a = this.config).recommendFeeMultiplier ?? (_a.recommendFeeMultiplier = 1.25);
23
23
  this.bitcoin = bitcoin;
@@ -108,7 +108,7 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
108
108
  }
109
109
  async processPastSwap(swap, tx, vout) {
110
110
  const foundVout = tx.outs[vout];
111
- const { swapContract, signer } = this.getChain(swap.chainIdentifier);
111
+ const { chainInterface, signer } = this.getChain(swap.chainIdentifier);
112
112
  const outputScript = this.bitcoin.toOutputScript(swap.btcAddress).toString("hex");
113
113
  if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.CREATED) {
114
114
  this.subscriptions.set(outputScript, swap);
@@ -220,7 +220,7 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
220
220
  }
221
221
  if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED) {
222
222
  //Send gas token
223
- const balance = swapContract.getBalance(signer.getAddress(), swap.token, false);
223
+ const balance = chainInterface.getBalance(signer.getAddress(), swap.token);
224
224
  try {
225
225
  await this.checkBalance(swap.adjustedOutput, balance, null);
226
226
  if (swap.metadata != null)
@@ -236,8 +236,8 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
236
236
  let unlock = swap.lock(30 * 1000);
237
237
  if (unlock == null)
238
238
  return;
239
- const txns = await swapContract.txsTransfer(signer.getAddress(), swap.token, swap.adjustedOutput, swap.dstAddress);
240
- await swapContract.sendAndConfirm(signer, txns, true, null, false, async (txId, rawTx) => {
239
+ const txns = await chainInterface.txsTransfer(signer.getAddress(), swap.token, swap.adjustedOutput, swap.dstAddress);
240
+ await chainInterface.sendAndConfirm(signer, txns, true, null, false, async (txId, rawTx) => {
241
241
  swap.txIds = { init: txId };
242
242
  swap.scRawTx = rawTx;
243
243
  if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.BTC_CONFIRMED) {
@@ -250,7 +250,7 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
250
250
  });
251
251
  }
252
252
  if (swap.state === FromBtcTrustedSwap_1.FromBtcTrustedSwapState.SENT) {
253
- const txStatus = await swapContract.getTxStatus(swap.scRawTx);
253
+ const txStatus = await chainInterface.getTxStatus(swap.scRawTx);
254
254
  switch (txStatus) {
255
255
  case "not_found":
256
256
  //Retry
@@ -335,7 +335,7 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
335
335
  var _a;
336
336
  const metadata = { request: {}, times: {} };
337
337
  const chainIdentifier = req.query.chain ?? this.chains.default;
338
- const { swapContract, signer } = this.getChain(chainIdentifier);
338
+ const { chainInterface, signer } = this.getChain(chainIdentifier);
339
339
  metadata.times.requestReceived = Date.now();
340
340
  /**
341
341
  * address: string solana address of the recipient
@@ -343,11 +343,11 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
343
343
  * amount: string amount (in lamports/smart chain base units) of the invoice
344
344
  * exactOut: boolean whether to create and exact output swap
345
345
  */
346
- (_a = req.query).token ?? (_a.token = swapContract.getNativeCurrencyAddress());
346
+ (_a = req.query).token ?? (_a.token = chainInterface.getNativeCurrencyAddress());
347
347
  const parsedBody = (0, SchemaVerifier_1.verifySchema)(req.query, {
348
348
  address: (val) => val != null &&
349
349
  typeof (val) === "string" &&
350
- swapContract.isValidAddress(val) ? val : null,
350
+ chainInterface.isValidAddress(val) ? val : null,
351
351
  refundAddress: (val) => val == null ? "" :
352
352
  typeof (val) === "string" &&
353
353
  this.isValidBitcoinAddress(val) ? val : null,
@@ -365,7 +365,7 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
365
365
  };
366
366
  metadata.request = parsedBody;
367
367
  const refundAddress = parsedBody.refundAddress === "" ? null : parsedBody.refundAddress;
368
- const requestedAmount = { input: parsedBody.exactIn, amount: parsedBody.amount };
368
+ const requestedAmount = { input: parsedBody.exactIn, amount: parsedBody.amount, token: parsedBody.token };
369
369
  const request = {
370
370
  chainIdentifier,
371
371
  raw: req,
@@ -374,20 +374,24 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
374
374
  };
375
375
  const useToken = parsedBody.token;
376
376
  //Check request params
377
- const fees = await this.preCheckAmounts(request, requestedAmount, useToken);
377
+ const fees = await this.AmountAssertions.preCheckFromBtcAmounts(this.type, request, requestedAmount);
378
378
  metadata.times.requestChecked = Date.now();
379
379
  //Create abortController for parallel prefetches
380
380
  const responseStream = res.responseStream;
381
- const abortController = this.getAbortController(responseStream);
381
+ const abortController = (0, Utils_1.getAbortController)(responseStream);
382
382
  //Pre-fetch data
383
- const { pricePrefetchPromise } = this.getFromBtcPricePrefetches(chainIdentifier, useToken, useToken, abortController);
384
- const balancePrefetch = swapContract.getBalance(signer.getAddress(), useToken, false).catch(e => {
383
+ const pricePrefetchPromise = this.swapPricing.preFetchPrice(useToken, chainIdentifier).catch(e => {
384
+ this.logger.error("pricePrefetchPromise(): pricePrefetch error: ", e);
385
+ abortController.abort(e);
386
+ return null;
387
+ });
388
+ const balancePrefetch = chainInterface.getBalance(signer.getAddress(), useToken).catch(e => {
385
389
  this.logger.error("getBalancePrefetch(): balancePrefetch error: ", e);
386
390
  abortController.abort(e);
387
391
  return null;
388
392
  });
389
393
  //Check valid amount specified (min/max)
390
- const { amountBD, swapFee, swapFeeInToken, totalInToken } = await this.checkFromBtcAmount(request, requestedAmount, fees, useToken, abortController.signal, pricePrefetchPromise);
394
+ const { amountBD, swapFee, swapFeeInToken, totalInToken } = await this.AmountAssertions.checkFromBtcAmount(this.type, request, { ...requestedAmount, pricePrefetch: pricePrefetchPromise }, fees, abortController.signal);
391
395
  metadata.times.priceCalculated = Date.now();
392
396
  //Make sure we have MORE THAN ENOUGH to honor the swap request
393
397
  await this.checkBalance(totalInToken * 4n, balancePrefetch, abortController.signal);
@@ -642,14 +646,5 @@ class FromBtcTrusted extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
642
646
  getInfoData() {
643
647
  return {};
644
648
  }
645
- processClaimEvent(chainIdentifier, swap, event) {
646
- return Promise.resolve(undefined);
647
- }
648
- processInitializeEvent(chainIdentifier, swap, event) {
649
- return Promise.resolve(undefined);
650
- }
651
- processRefundEvent(chainIdentifier, swap, event) {
652
- return Promise.resolve(undefined);
653
- }
654
649
  }
655
650
  exports.FromBtcTrusted = FromBtcTrusted;
@@ -1,5 +1,5 @@
1
- import { BtcTx, SwapData } from "@atomiqlabs/base";
2
- import { FromBtcBaseSwap } from "../FromBtcBaseSwap";
1
+ import { BtcTx } from "@atomiqlabs/base";
2
+ import { SwapHandlerSwap } from "../../SwapHandlerSwap";
3
3
  export declare enum FromBtcTrustedSwapState {
4
4
  DOUBLE_SPENT = -4,
5
5
  REFUNDED = -3,
@@ -12,7 +12,8 @@ export declare enum FromBtcTrustedSwapState {
12
12
  CONFIRMED = 4,
13
13
  FINISHED = 5
14
14
  }
15
- export declare class FromBtcTrustedSwap<T extends SwapData = SwapData> extends FromBtcBaseSwap<T, FromBtcTrustedSwapState> {
15
+ export declare class FromBtcTrustedSwap extends SwapHandlerSwap<FromBtcTrustedSwapState> {
16
+ readonly amount: bigint;
16
17
  readonly sequence: bigint;
17
18
  readonly btcAddress: string;
18
19
  readonly dstAddress: string;
@@ -36,12 +37,16 @@ export declare class FromBtcTrustedSwap<T extends SwapData = SwapData> extends F
36
37
  constructor(chainIdentifier: string, swapFee: bigint, swapFeeInToken: bigint, btcAddress: string, inputSats: bigint, dstAddress: string, outputTokens: bigint, createdHeight: number, expiresAt: number, recommendedFee: number, refundAddress: string, token: string);
37
38
  constructor(obj: any);
38
39
  serialize(): any;
39
- getClaimHash(): string;
40
40
  getSequence(): bigint;
41
41
  getToken(): string;
42
42
  getOutputAmount(): bigint;
43
43
  getTotalInputAmount(): bigint;
44
+ getSwapFee(): {
45
+ inInputToken: bigint;
46
+ inOutputToken: bigint;
47
+ };
44
48
  isFailed(): boolean;
45
49
  isInitiated(): boolean;
46
50
  isSuccess(): boolean;
51
+ getIdentifierHash(): string;
47
52
  }