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