@atomiqlabs/lp-lib 10.3.11 → 11.0.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 +3 -1
- package/dist/index.js +3 -4
- package/dist/plugins/IPlugin.d.ts +3 -2
- package/dist/plugins/PluginManager.d.ts +3 -2
- package/dist/plugins/PluginManager.js +2 -2
- package/dist/prices/OKXSwapPrice.d.ts +27 -0
- package/dist/prices/OKXSwapPrice.js +106 -0
- package/dist/swaps/FromBtcBaseSwap.d.ts +5 -1
- package/dist/swaps/FromBtcBaseSwap.js +20 -0
- package/dist/swaps/FromBtcBaseSwapHandler.d.ts +1 -0
- package/dist/swaps/FromBtcBaseSwapHandler.js +1 -1
- package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +8 -6
- package/dist/swaps/FromBtcLnBaseSwapHandler.js +7 -5
- package/dist/swaps/SwapHandler.d.ts +1 -4
- package/dist/swaps/SwapHandler.js +1 -2
- package/dist/swaps/SwapHandlerSwap.d.ts +4 -0
- package/dist/swaps/SwapHandlerSwap.js +9 -1
- package/dist/swaps/ToBtcBaseSwap.d.ts +3 -1
- package/dist/swaps/ToBtcBaseSwap.js +8 -2
- package/dist/swaps/ToBtcBaseSwapHandler.d.ts +1 -0
- package/dist/swaps/ToBtcBaseSwapHandler.js +1 -1
- package/dist/swaps/frombtc_abstract/FromBtcAbs.d.ts +3 -5
- package/dist/swaps/frombtc_abstract/FromBtcAbs.js +18 -25
- package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.d.ts +1 -4
- package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.js +3 -16
- package/dist/swaps/frombtc_trusted/FromBtcTrusted.d.ts +6 -9
- package/dist/swaps/frombtc_trusted/FromBtcTrusted.js +238 -137
- package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.d.ts +9 -6
- package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.js +15 -10
- package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.d.ts +2 -2
- package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.js +42 -62
- package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +1 -6
- package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.js +2 -14
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.d.ts +3 -5
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.js +90 -87
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.d.ts +1 -2
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.js +5 -8
- package/dist/swaps/tobtc_abstract/ToBtcAbs.d.ts +5 -125
- package/dist/swaps/tobtc_abstract/ToBtcAbs.js +41 -334
- package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.d.ts +1 -4
- package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.js +2 -11
- package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.d.ts +5 -55
- package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.js +152 -398
- package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.d.ts +1 -6
- package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.js +2 -15
- package/dist/utils/Utils.d.ts +0 -10
- package/dist/utils/Utils.js +1 -34
- package/dist/wallets/IBitcoinWallet.d.ts +62 -0
- package/dist/wallets/IBitcoinWallet.js +2 -0
- package/dist/wallets/ILightningWallet.d.ts +118 -0
- package/dist/wallets/ILightningWallet.js +37 -0
- package/package.json +4 -9
- package/src/index.ts +4 -5
- package/src/plugins/IPlugin.ts +4 -2
- package/src/plugins/PluginManager.ts +6 -3
- package/src/prices/OKXSwapPrice.ts +114 -0
- package/src/swaps/FromBtcBaseSwap.ts +24 -1
- package/src/swaps/FromBtcBaseSwapHandler.ts +6 -2
- package/src/swaps/FromBtcLnBaseSwapHandler.ts +22 -6
- package/src/swaps/SwapHandler.ts +1 -8
- package/src/swaps/SwapHandlerSwap.ts +14 -1
- package/src/swaps/ToBtcBaseSwap.ts +12 -3
- package/src/swaps/ToBtcBaseSwapHandler.ts +6 -2
- package/src/swaps/frombtc_abstract/FromBtcAbs.ts +24 -28
- package/src/swaps/frombtc_abstract/FromBtcSwapAbs.ts +3 -18
- package/src/swaps/frombtc_trusted/FromBtcTrusted.ts +260 -159
- package/src/swaps/frombtc_trusted/FromBtcTrustedSwap.ts +22 -15
- package/src/swaps/frombtcln_abstract/FromBtcLnAbs.ts +69 -79
- package/src/swaps/frombtcln_abstract/FromBtcLnSwapAbs.ts +3 -20
- package/src/swaps/frombtcln_trusted/FromBtcLnTrusted.ts +108 -103
- package/src/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.ts +6 -9
- package/src/swaps/tobtc_abstract/ToBtcAbs.ts +52 -410
- package/src/swaps/tobtc_abstract/ToBtcSwapAbs.ts +3 -18
- package/src/swaps/tobtcln_abstract/ToBtcLnAbs.ts +157 -434
- package/src/swaps/tobtcln_abstract/ToBtcLnSwapAbs.ts +3 -20
- package/src/utils/Utils.ts +0 -31
- package/src/wallets/IBitcoinWallet.ts +66 -0
- package/src/wallets/ILightningWallet.ts +179 -0
- package/dist/fees/OneDollarFeeEstimator.d.ts +0 -16
- package/dist/fees/OneDollarFeeEstimator.js +0 -71
- package/dist/utils/coinselect2/accumulative.d.ts +0 -6
- package/dist/utils/coinselect2/accumulative.js +0 -44
- package/dist/utils/coinselect2/blackjack.d.ts +0 -6
- package/dist/utils/coinselect2/blackjack.js +0 -41
- package/dist/utils/coinselect2/index.d.ts +0 -16
- package/dist/utils/coinselect2/index.js +0 -40
- package/dist/utils/coinselect2/utils.d.ts +0 -64
- package/dist/utils/coinselect2/utils.js +0 -121
- package/src/fees/OneDollarFeeEstimator.ts +0 -95
- package/src/utils/coinselect2/accumulative.js +0 -32
- package/src/utils/coinselect2/accumulative.ts +0 -58
- package/src/utils/coinselect2/blackjack.js +0 -29
- package/src/utils/coinselect2/blackjack.ts +0 -54
- package/src/utils/coinselect2/index.js +0 -16
- package/src/utils/coinselect2/index.ts +0 -50
- package/src/utils/coinselect2/utils.js +0 -110
- package/src/utils/coinselect2/utils.ts +0 -183
|
@@ -1,41 +1,36 @@
|
|
|
1
1
|
import {FromBtcBaseConfig, FromBtcBaseSwapHandler} from "../FromBtcBaseSwapHandler";
|
|
2
2
|
import {FromBtcTrustedSwap, FromBtcTrustedSwapState} from "./FromBtcTrustedSwap";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
BitcoinRpc,
|
|
5
|
+
BtcBlock,
|
|
6
|
+
BtcTx,
|
|
7
|
+
BtcVout,
|
|
8
|
+
ClaimEvent,
|
|
9
|
+
InitializeEvent,
|
|
10
|
+
RefundEvent,
|
|
11
|
+
SwapData
|
|
12
|
+
} from "@atomiqlabs/base";
|
|
4
13
|
import {Express, Request, Response} from "express";
|
|
5
14
|
import {MultichainData, SwapHandlerType} from "../SwapHandler";
|
|
6
15
|
import * as BN from "bn.js";
|
|
7
16
|
import {IIntermediaryStorage} from "../../storage/IIntermediaryStorage";
|
|
8
|
-
import {
|
|
9
|
-
AuthenticatedLnd,
|
|
10
|
-
broadcastChainTransaction,
|
|
11
|
-
ChainTransaction, createChainAddress, createHodlInvoice,
|
|
12
|
-
getChainTransactions, getHeight,
|
|
13
|
-
signPsbt,
|
|
14
|
-
subscribeToTransactions, SubscribeToTransactionsChainTransactionEvent
|
|
15
|
-
} from "lightning";
|
|
16
17
|
import {ISwapPrice} from "../ISwapPrice";
|
|
17
18
|
import {PluginManager} from "../../plugins/PluginManager";
|
|
18
|
-
import {address, networks, Psbt, Transaction, TxOutput} from "bitcoinjs-lib";
|
|
19
|
-
import {IBtcFeeEstimator} from "../../fees/IBtcFeeEstimator";
|
|
20
|
-
import {utils} from "../../utils/coinselect2/utils";
|
|
21
19
|
import {expressHandlerWrapper, HEX_REGEX} from "../../utils/Utils";
|
|
22
20
|
import {IParamReader} from "../../utils/paramcoders/IParamReader";
|
|
23
21
|
import {ServerParamEncoder} from "../../utils/paramcoders/server/ServerParamEncoder";
|
|
24
22
|
import {FieldTypeEnum, verifySchema} from "../../utils/paramcoders/SchemaVerifier";
|
|
25
|
-
import * as bitcoin from "bitcoinjs-lib";
|
|
26
23
|
import {serverParamDecoder} from "../../utils/paramcoders/server/ServerParamDecoder";
|
|
24
|
+
import {IBitcoinWallet} from "../../wallets/IBitcoinWallet";
|
|
27
25
|
|
|
28
26
|
export type FromBtcTrustedConfig = FromBtcBaseConfig & {
|
|
29
|
-
bitcoinNetwork: networks.Network,
|
|
30
|
-
feeEstimator: IBtcFeeEstimator,
|
|
31
27
|
doubleSpendCheckInterval: number,
|
|
32
28
|
swapAddressExpiry: number,
|
|
33
|
-
recommendFeeMultiplier?: number
|
|
29
|
+
recommendFeeMultiplier?: number
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
export type FromBtcTrustedRequestType = {
|
|
37
33
|
address: string,
|
|
38
|
-
refundAddress: string,
|
|
39
34
|
amount: BN,
|
|
40
35
|
exactOut?: boolean
|
|
41
36
|
};
|
|
@@ -44,6 +39,7 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
44
39
|
readonly type: SwapHandlerType = SwapHandlerType.FROM_BTC_TRUSTED;
|
|
45
40
|
|
|
46
41
|
readonly config: FromBtcTrustedConfig;
|
|
42
|
+
readonly bitcoin: IBitcoinWallet;
|
|
47
43
|
readonly bitcoinRpc: BitcoinRpc<BtcBlock>;
|
|
48
44
|
|
|
49
45
|
readonly subscriptions: Map<string, FromBtcTrustedSwap> = new Map<string, FromBtcTrustedSwap>();
|
|
@@ -51,81 +47,72 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
51
47
|
|
|
52
48
|
readonly refundedSwaps: Map<string, string> = new Map();
|
|
53
49
|
readonly doubleSpentSwaps: Map<string, string> = new Map();
|
|
54
|
-
readonly processedTxIds: Map<string, { txId: string, adjustedAmount: BN, adjustedTotal: BN }> = new Map();
|
|
50
|
+
readonly processedTxIds: Map<string, { scTxId: string, txId: string, adjustedAmount: BN, adjustedTotal: BN }> = new Map();
|
|
55
51
|
|
|
56
52
|
constructor(
|
|
57
53
|
storageDirectory: IIntermediaryStorage<FromBtcTrustedSwap>,
|
|
58
54
|
path: string,
|
|
59
55
|
chains: MultichainData,
|
|
60
|
-
|
|
56
|
+
bitcoin: IBitcoinWallet,
|
|
61
57
|
swapPricing: ISwapPrice,
|
|
62
58
|
bitcoinRpc: BitcoinRpc<BtcBlock>,
|
|
63
59
|
config: FromBtcTrustedConfig
|
|
64
60
|
) {
|
|
65
|
-
super(storageDirectory, path, chains,
|
|
61
|
+
super(storageDirectory, path, chains, swapPricing);
|
|
66
62
|
this.config = config;
|
|
67
63
|
this.config.recommendFeeMultiplier ??= 1.25;
|
|
64
|
+
this.bitcoin = bitcoin;
|
|
68
65
|
this.bitcoinRpc = bitcoinRpc;
|
|
69
66
|
for(let chainId in chains.chains) {
|
|
70
67
|
this.allowedTokens[chainId] = new Set<string>([chains.chains[chainId].swapContract.getNativeCurrencyAddress()]);
|
|
71
68
|
}
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
private getAllAncestors(tx:
|
|
75
|
-
return Promise.all(tx.
|
|
76
|
-
return {tx, vout: input.
|
|
71
|
+
private getAllAncestors(tx: BtcTx): Promise<{tx: BtcTx, vout: number}[]> {
|
|
72
|
+
return Promise.all(tx.ins.map(input => this.bitcoinRpc.getTransaction(input.txid).then(tx => {
|
|
73
|
+
return {tx, vout: input.vout}
|
|
77
74
|
})));
|
|
78
75
|
}
|
|
79
76
|
|
|
80
77
|
private async refundSwap(swap: FromBtcTrustedSwap) {
|
|
78
|
+
if(swap.refundAddress==null) {
|
|
79
|
+
if(swap.state!==FromBtcTrustedSwapState.REFUNDABLE) {
|
|
80
|
+
await swap.setState(FromBtcTrustedSwapState.REFUNDABLE);
|
|
81
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
81
86
|
let unlock = swap.lock(30*1000);
|
|
82
87
|
if(unlock==null) return;
|
|
83
88
|
|
|
84
|
-
const feeRate = await this.
|
|
89
|
+
const feeRate = await this.bitcoin.getFeeRate();
|
|
85
90
|
|
|
86
|
-
const
|
|
87
|
-
const ourOutput = initialTx.outs[swap.vout];
|
|
91
|
+
const ourOutput = swap.btcTx.outs[swap.vout];
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const resp = await this.bitcoin.drainAll(swap.refundAddress, [{
|
|
94
|
+
type: this.bitcoin.getAddressType(),
|
|
95
|
+
confirmations: swap.btcTx.confirmations,
|
|
96
|
+
outputScript: Buffer.from(ourOutput.scriptPubKey.hex, "hex"),
|
|
97
|
+
value: ourOutput.value,
|
|
98
|
+
txId: swap.btcTx.txid,
|
|
99
|
+
vout: swap.vout
|
|
100
|
+
}], feeRate);
|
|
101
|
+
|
|
102
|
+
if(resp==null) {
|
|
95
103
|
this.swapLogger.error(swap, "refundSwap(): cannot refund swap because of dust limit, txId: "+swap.txId);
|
|
96
104
|
unlock();
|
|
97
105
|
return;
|
|
98
106
|
}
|
|
99
107
|
|
|
100
|
-
//Construct PSBT
|
|
101
|
-
const _psbt = new Psbt({network: this.config.bitcoinNetwork});
|
|
102
|
-
_psbt.addInput({
|
|
103
|
-
hash: initialTx.getHash(),
|
|
104
|
-
index: swap.vout,
|
|
105
|
-
witnessUtxo: ourOutput,
|
|
106
|
-
sighashType: 0x01,
|
|
107
|
-
sequence: 0xfffffffd
|
|
108
|
-
});
|
|
109
|
-
_psbt.addOutput({
|
|
110
|
-
script: refundOutputScript,
|
|
111
|
-
value: adjustedOutput
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
//Sign
|
|
115
|
-
const {psbt, transaction} = await signPsbt({
|
|
116
|
-
lnd: this.LND,
|
|
117
|
-
psbt: _psbt.toHex()
|
|
118
|
-
});
|
|
119
108
|
if(swap.metadata!=null) swap.metadata.times.refundSignPSBT = Date.now();
|
|
120
|
-
this.swapLogger.debug(swap, "refundSwap(): signed raw transaction: "+
|
|
109
|
+
this.swapLogger.debug(swap, "refundSwap(): signed raw transaction: "+resp.raw);
|
|
121
110
|
|
|
122
|
-
const
|
|
123
|
-
const refundTxId = signedTx.getId();
|
|
111
|
+
const refundTxId = resp.txId;
|
|
124
112
|
swap.refundTxId = refundTxId;
|
|
125
113
|
|
|
126
114
|
//Send the refund TX
|
|
127
|
-
await
|
|
128
|
-
|
|
115
|
+
await this.bitcoin.sendRawTransaction(resp.raw);
|
|
129
116
|
this.swapLogger.debug(swap, "refundSwap(): sent refund transaction: "+refundTxId);
|
|
130
117
|
|
|
131
118
|
this.refundedSwaps.set(swap.getHash(), refundTxId);
|
|
@@ -134,128 +121,143 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
134
121
|
}
|
|
135
122
|
|
|
136
123
|
private async burn(swap: FromBtcTrustedSwap) {
|
|
137
|
-
const
|
|
138
|
-
|
|
124
|
+
const ourOutput = swap.btcTx.outs[swap.vout];
|
|
125
|
+
|
|
126
|
+
//Check if we can even increase the feeRate by burning
|
|
127
|
+
const txSize = 110;
|
|
128
|
+
const burnTxFeeRate = Math.floor(ourOutput.value/txSize);
|
|
129
|
+
const initialTxFeeRate = Math.ceil(swap.txFee/swap.txSize);
|
|
130
|
+
|
|
131
|
+
if(burnTxFeeRate<initialTxFeeRate) {
|
|
132
|
+
this.swapLogger.warn(swap, "burn(): cannot send burn transaction, pays too little fee, " +
|
|
133
|
+
"initialTxId: "+swap.txId+" initialTxFeeRate: "+initialTxFeeRate+" burnTxFeeRate: "+burnTxFeeRate);
|
|
134
|
+
this.doubleSpentSwaps.set(swap.getHash(), null);
|
|
135
|
+
await this.removeSwapData(swap, FromBtcTrustedSwapState.DOUBLE_SPENT);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
139
138
|
|
|
140
139
|
//Construct PSBT
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
});
|
|
149
|
-
_psbt.addOutput({
|
|
150
|
-
script: Buffer.concat([Buffer.from([0x6a, 20]), Buffer.from("BURN, BABY, BURN! AQ", "ascii")]),
|
|
151
|
-
value: 0
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
//Sign
|
|
155
|
-
const {psbt, transaction} = await signPsbt({
|
|
156
|
-
lnd: this.LND,
|
|
157
|
-
psbt: _psbt.toHex()
|
|
158
|
-
});
|
|
140
|
+
const resp = await this.bitcoin.burnAll([{
|
|
141
|
+
type: this.bitcoin.getAddressType(),
|
|
142
|
+
confirmations: swap.btcTx.confirmations,
|
|
143
|
+
outputScript: Buffer.from(ourOutput.scriptPubKey.hex, "hex"),
|
|
144
|
+
value: ourOutput.value,
|
|
145
|
+
txId: swap.btcTx.txid,
|
|
146
|
+
vout: swap.vout
|
|
147
|
+
}]);
|
|
159
148
|
if(swap.metadata!=null) swap.metadata.times.burnSignPSBT = Date.now();
|
|
160
|
-
this.swapLogger.debug(swap, "burn(): signed raw transaction: "+
|
|
149
|
+
this.swapLogger.debug(swap, "burn(): signed raw transaction: "+resp.raw);
|
|
161
150
|
|
|
162
|
-
const
|
|
163
|
-
const burnTxId = signedTx.getId();
|
|
151
|
+
const burnTxId = resp.txId;
|
|
164
152
|
swap.burnTxId = burnTxId;
|
|
165
153
|
|
|
166
154
|
//Send the original TX + our burn TX as a package
|
|
167
|
-
const sendTxns = [swap.
|
|
168
|
-
|
|
155
|
+
const sendTxns = [swap.btcTx.raw, resp.raw];
|
|
156
|
+
//TODO: We should handle this in a better way
|
|
157
|
+
try {
|
|
158
|
+
await this.bitcoinRpc.sendRawPackage(sendTxns);
|
|
159
|
+
this.swapLogger.debug(swap, "burn(): sent burn transaction: "+burnTxId);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
this.swapLogger.error(swap, "burn(): error sending burn package: ", e);
|
|
162
|
+
}
|
|
169
163
|
|
|
170
|
-
this.swapLogger.debug(swap, "burn(): sent burn transaction: "+burnTxId);
|
|
171
164
|
this.doubleSpentSwaps.set(swap.getHash(), burnTxId);
|
|
172
165
|
await this.removeSwapData(swap, FromBtcTrustedSwapState.DOUBLE_SPENT);
|
|
173
166
|
}
|
|
174
167
|
|
|
175
|
-
protected async processPastSwap(swap: FromBtcTrustedSwap, tx:
|
|
176
|
-
|
|
177
|
-
let foundVout: TxOutput = null;
|
|
178
|
-
let vout: number = -1;
|
|
179
|
-
if(tx!=null) {
|
|
180
|
-
parsedTx = Transaction.fromHex(tx.transaction);
|
|
181
|
-
const requiredOutputScript = address.toOutputScript(swap.btcAddress, this.config.bitcoinNetwork);
|
|
182
|
-
vout = parsedTx.outs.findIndex(vout => vout.script.equals(requiredOutputScript));
|
|
183
|
-
if(vout!==-1) foundVout = parsedTx.outs[vout];
|
|
184
|
-
}
|
|
168
|
+
protected async processPastSwap(swap: FromBtcTrustedSwap, tx: BtcTx | null, vout: number | null): Promise<void> {
|
|
169
|
+
const foundVout: BtcVout = tx.outs[vout];
|
|
185
170
|
|
|
186
171
|
const {swapContract, signer} = this.getChain(swap.chainIdentifier);
|
|
187
172
|
|
|
173
|
+
const outputScript = this.bitcoin.toOutputScript(swap.btcAddress).toString("hex");
|
|
174
|
+
|
|
188
175
|
if(swap.state===FromBtcTrustedSwapState.CREATED) {
|
|
189
|
-
this.subscriptions.set(
|
|
176
|
+
this.subscriptions.set(outputScript, swap);
|
|
190
177
|
if(foundVout==null) {
|
|
191
178
|
//Check expiry
|
|
192
179
|
if(swap.expiresAt<Date.now()) {
|
|
193
|
-
this.subscriptions.delete(
|
|
180
|
+
this.subscriptions.delete(outputScript);
|
|
181
|
+
await this.bitcoin.addUnusedAddress(swap.btcAddress);
|
|
194
182
|
await this.removeSwapData(swap, FromBtcTrustedSwapState.EXPIRED);
|
|
195
183
|
return;
|
|
196
184
|
}
|
|
197
185
|
return;
|
|
198
186
|
}
|
|
199
187
|
const sentSats = new BN(foundVout.value);
|
|
200
|
-
if(sentSats.eq(swap.
|
|
201
|
-
swap.adjustedInput = swap.
|
|
188
|
+
if(sentSats.eq(swap.amount)) {
|
|
189
|
+
swap.adjustedInput = swap.amount;
|
|
202
190
|
swap.adjustedOutput = swap.outputTokens;
|
|
203
191
|
} else {
|
|
204
192
|
//If lower than minimum then ignore
|
|
205
193
|
if(sentSats.lt(this.config.min)) return;
|
|
206
194
|
if(sentSats.gt(this.config.max)) {
|
|
207
|
-
swap.
|
|
208
|
-
swap.
|
|
195
|
+
swap.adjustedInput = sentSats;
|
|
196
|
+
swap.btcTx = tx;
|
|
197
|
+
swap.txId = tx.txid;
|
|
209
198
|
swap.vout = vout;
|
|
210
|
-
this.subscriptions.delete(
|
|
199
|
+
this.subscriptions.delete(outputScript);
|
|
211
200
|
await this.refundSwap(swap);
|
|
212
201
|
return;
|
|
213
202
|
}
|
|
214
203
|
//Adjust the amount
|
|
215
204
|
swap.adjustedInput = sentSats;
|
|
216
|
-
swap.adjustedOutput = swap.outputTokens.mul(sentSats).div(swap.
|
|
205
|
+
swap.adjustedOutput = swap.outputTokens.mul(sentSats).div(swap.amount);
|
|
217
206
|
}
|
|
218
|
-
swap.
|
|
219
|
-
swap.txId = tx.
|
|
207
|
+
swap.btcTx = tx;
|
|
208
|
+
swap.txId = tx.txid;
|
|
220
209
|
swap.vout = vout;
|
|
221
|
-
this.subscriptions.delete(
|
|
210
|
+
this.subscriptions.delete(outputScript);
|
|
222
211
|
await swap.setState(FromBtcTrustedSwapState.RECEIVED);
|
|
223
|
-
await this.storageManager.saveData(swap.getHash(),
|
|
212
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
224
213
|
}
|
|
225
214
|
|
|
226
215
|
if(swap.state===FromBtcTrustedSwapState.RECEIVED) {
|
|
227
216
|
//Check if transaction still exists
|
|
228
|
-
if(tx==null || foundVout==null || tx.
|
|
217
|
+
if(tx==null || foundVout==null || tx.txid!==swap.txId) {
|
|
229
218
|
await swap.setState(FromBtcTrustedSwapState.CREATED);
|
|
230
|
-
await this.storageManager.saveData(swap.getHash(),
|
|
219
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
231
220
|
return;
|
|
232
221
|
}
|
|
233
222
|
//Check if it is confirmed
|
|
234
|
-
if(tx.
|
|
223
|
+
if(tx.confirmations>0) {
|
|
235
224
|
await swap.setState(FromBtcTrustedSwapState.BTC_CONFIRMED);
|
|
236
|
-
await this.storageManager.saveData(swap.getHash(),
|
|
225
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
237
226
|
} else {
|
|
238
227
|
//Check if it pays high enough fee AND has confirmed ancestors
|
|
239
228
|
const ancestors = await this.getAllAncestors(tx);
|
|
240
229
|
const allAncestorsConfirmed = ancestors.reduce((prev, curr) => prev && curr.tx.confirmations>0, true);
|
|
241
230
|
const totalInput = ancestors.reduce((prev, curr) => prev + curr.tx.outs[curr.vout].value, 0);
|
|
242
|
-
const totalOutput =
|
|
231
|
+
const totalOutput = tx.outs.reduce((prev, curr) => prev + curr.value, 0);
|
|
243
232
|
const fee = totalInput-totalOutput;
|
|
244
|
-
const feePerVbyte = Math.ceil(fee/
|
|
233
|
+
const feePerVbyte = Math.ceil(fee/tx.vsize);
|
|
245
234
|
if(
|
|
246
235
|
allAncestorsConfirmed &&
|
|
247
|
-
(feePerVbyte>=swap.recommendedFee || feePerVbyte>=await this.
|
|
236
|
+
(feePerVbyte>=swap.recommendedFee || feePerVbyte>=await this.bitcoin.getFeeRate())
|
|
248
237
|
) {
|
|
249
238
|
if(swap.state!==FromBtcTrustedSwapState.RECEIVED) return;
|
|
239
|
+
swap.txSize = tx.vsize;
|
|
240
|
+
swap.txFee = fee;
|
|
250
241
|
await swap.setState(FromBtcTrustedSwapState.BTC_CONFIRMED);
|
|
251
|
-
await this.storageManager.saveData(swap.getHash(),
|
|
242
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
252
243
|
} else {
|
|
253
244
|
return;
|
|
254
245
|
}
|
|
255
246
|
}
|
|
256
247
|
}
|
|
257
248
|
|
|
258
|
-
if(swap.
|
|
249
|
+
if(swap.state===FromBtcTrustedSwapState.REFUNDABLE) {
|
|
250
|
+
if(swap.refundAddress!=null) {
|
|
251
|
+
await this.refundSwap(swap);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if(swap.doubleSpent || tx==null || foundVout==null || tx.txid!==swap.txId) {
|
|
257
|
+
if(swap.state===FromBtcTrustedSwapState.REFUNDABLE) {
|
|
258
|
+
await swap.setState(FromBtcTrustedSwapState.CREATED);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
259
261
|
if(!swap.doubleSpent) {
|
|
260
262
|
swap.doubleSpent = true;
|
|
261
263
|
try {
|
|
@@ -268,14 +270,13 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
268
270
|
}
|
|
269
271
|
return;
|
|
270
272
|
} else {
|
|
271
|
-
if(!this.doubleSpendWatchdogSwaps.has(swap)) {
|
|
273
|
+
if(tx.confirmations<=0 && !this.doubleSpendWatchdogSwaps.has(swap)) {
|
|
272
274
|
this.swapLogger.debug(swap, "processPastSwap(): Adding swap transaction to double spend watchdog list: ", swap.txId);
|
|
273
275
|
this.doubleSpendWatchdogSwaps.add(swap);
|
|
274
276
|
}
|
|
275
277
|
}
|
|
276
|
-
if(tx.
|
|
278
|
+
if(tx.confirmations>0 && this.doubleSpendWatchdogSwaps.delete(swap)) {
|
|
277
279
|
this.swapLogger.debug(swap, "processPastSwap(): Removing confirmed swap transaction from double spend watchdog list: ", swap.txId);
|
|
278
|
-
this.doubleSpendWatchdogSwaps.delete(swap);
|
|
279
280
|
}
|
|
280
281
|
|
|
281
282
|
if(swap.state===FromBtcTrustedSwapState.BTC_CONFIRMED) {
|
|
@@ -301,7 +302,7 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
301
302
|
swap.scRawTx = rawTx;
|
|
302
303
|
if(swap.state===FromBtcTrustedSwapState.BTC_CONFIRMED) {
|
|
303
304
|
await swap.setState(FromBtcTrustedSwapState.SENT);
|
|
304
|
-
await this.storageManager.saveData(swap.getHash(),
|
|
305
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
305
306
|
}
|
|
306
307
|
if(unlock!=null) unlock();
|
|
307
308
|
unlock = null;
|
|
@@ -316,7 +317,7 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
316
317
|
swap.txIds = {init: null};
|
|
317
318
|
swap.scRawTx = null;
|
|
318
319
|
await swap.setState(FromBtcTrustedSwapState.RECEIVED);
|
|
319
|
-
await this.storageManager.saveData(swap.getHash(),
|
|
320
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
320
321
|
break;
|
|
321
322
|
case "reverted":
|
|
322
323
|
//Cancel invoice
|
|
@@ -325,18 +326,19 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
325
326
|
break;
|
|
326
327
|
case "success":
|
|
327
328
|
await swap.setState(FromBtcTrustedSwapState.CONFIRMED);
|
|
328
|
-
await this.storageManager.saveData(swap.getHash(),
|
|
329
|
+
await this.storageManager.saveData(swap.getHash(), swap.getSequence(), swap);
|
|
329
330
|
break;
|
|
330
331
|
}
|
|
331
332
|
}
|
|
332
333
|
|
|
333
334
|
if(swap.state===FromBtcTrustedSwapState.CONFIRMED) {
|
|
334
335
|
this.processedTxIds.set(swap.getHash(), {
|
|
335
|
-
txId: swap.
|
|
336
|
+
txId: swap.txId,
|
|
337
|
+
scTxId: swap.txIds.init,
|
|
336
338
|
adjustedAmount: swap.adjustedInput,
|
|
337
339
|
adjustedTotal: swap.adjustedOutput
|
|
338
340
|
});
|
|
339
|
-
if(tx.
|
|
341
|
+
if(tx.confirmations>0) await this.removeSwapData(swap, FromBtcTrustedSwapState.FINISHED);
|
|
340
342
|
}
|
|
341
343
|
}
|
|
342
344
|
|
|
@@ -345,6 +347,7 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
345
347
|
{
|
|
346
348
|
key: "state",
|
|
347
349
|
value: [
|
|
350
|
+
FromBtcTrustedSwapState.REFUNDABLE,
|
|
348
351
|
FromBtcTrustedSwapState.CREATED,
|
|
349
352
|
FromBtcTrustedSwapState.RECEIVED,
|
|
350
353
|
FromBtcTrustedSwapState.BTC_CONFIRMED,
|
|
@@ -356,17 +359,34 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
356
359
|
|
|
357
360
|
const startingBlockheight = queriedData.reduce((prev, swap) => Math.min(prev, swap.createdHeight), Infinity);
|
|
358
361
|
if(startingBlockheight===Infinity) return;
|
|
359
|
-
const
|
|
362
|
+
const transactions = await this.bitcoin.getWalletTransactions(startingBlockheight);
|
|
363
|
+
|
|
364
|
+
const map = new Map<string, {tx: BtcTx, vout: number}[]>();
|
|
365
|
+
transactions.forEach(tx => {
|
|
366
|
+
tx.outs.forEach((out, vout) => {
|
|
367
|
+
const existing = map.get(out.scriptPubKey.hex);
|
|
368
|
+
if(existing==null) {
|
|
369
|
+
map.set(out.scriptPubKey.hex, [{tx, vout}]);
|
|
370
|
+
} else {
|
|
371
|
+
existing.push({tx, vout});
|
|
372
|
+
}
|
|
373
|
+
})
|
|
374
|
+
});
|
|
360
375
|
|
|
361
376
|
for(let swap of queriedData) {
|
|
362
|
-
const
|
|
363
|
-
|
|
377
|
+
const outputScript = this.bitcoin.toOutputScript(swap.btcAddress).toString("hex");
|
|
378
|
+
const txs = map.get(outputScript) ?? [];
|
|
379
|
+
try {
|
|
380
|
+
await this.processPastSwap(swap, txs[0]?.tx, txs[0]?.vout);
|
|
381
|
+
} catch (e) {
|
|
382
|
+
this.swapLogger.error(swap, "processPastSwaps(): Error ocurred while processing swap: ", e);
|
|
383
|
+
}
|
|
364
384
|
}
|
|
365
385
|
}
|
|
366
386
|
|
|
367
387
|
private isValidBitcoinAddress(address: string) {
|
|
368
388
|
try {
|
|
369
|
-
bitcoin.
|
|
389
|
+
this.bitcoin.toOutputScript(address);
|
|
370
390
|
return true;
|
|
371
391
|
} catch (e) {}
|
|
372
392
|
return false;
|
|
@@ -388,18 +408,14 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
388
408
|
metadata.times.requestReceived = Date.now();
|
|
389
409
|
/**
|
|
390
410
|
* address: string solana address of the recipient
|
|
391
|
-
* refundAddress
|
|
411
|
+
* refundAddress?: string bitcoin address to use in case of refund
|
|
392
412
|
* amount: string amount (in lamports/smart chain base units) of the invoice
|
|
393
413
|
* exactOut: boolean whether to create and exact output swap
|
|
394
414
|
*/
|
|
395
|
-
|
|
396
415
|
const parsedBody: FromBtcTrustedRequestType = await req.paramReader.getParams({
|
|
397
416
|
address: (val: string) => val!=null &&
|
|
398
417
|
typeof(val)==="string" &&
|
|
399
418
|
swapContract.isValidAddress(val) ? val : null,
|
|
400
|
-
refundAddress: (val: string) => val!=null &&
|
|
401
|
-
typeof(val)==="string" &&
|
|
402
|
-
this.isValidBitcoinAddress(val) ? val : null,
|
|
403
419
|
amount: FieldTypeEnum.BN,
|
|
404
420
|
exactOut: FieldTypeEnum.BooleanOptional
|
|
405
421
|
});
|
|
@@ -409,6 +425,13 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
409
425
|
};
|
|
410
426
|
metadata.request = parsedBody;
|
|
411
427
|
|
|
428
|
+
const refundAddressData = req.paramReader.getExistingParamsOrNull({
|
|
429
|
+
refundAddress: (val: string) => val!=null &&
|
|
430
|
+
typeof(val)==="string" &&
|
|
431
|
+
this.isValidBitcoinAddress(val) ? val : null
|
|
432
|
+
});
|
|
433
|
+
const refundAddress = refundAddressData?.refundAddress;
|
|
434
|
+
|
|
412
435
|
const requestedAmount = {input: !parsedBody.exactOut, amount: parsedBody.amount};
|
|
413
436
|
const request = {
|
|
414
437
|
chainIdentifier,
|
|
@@ -443,21 +466,25 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
443
466
|
} = await this.checkFromBtcAmount(request, requestedAmount, fees, useToken, abortController.signal, pricePrefetchPromise);
|
|
444
467
|
metadata.times.priceCalculated = Date.now();
|
|
445
468
|
|
|
446
|
-
//
|
|
447
|
-
await this.checkBalance(totalInToken, balancePrefetch, abortController.signal)
|
|
469
|
+
//Make sure we have MORE THAN ENOUGH to honor the swap request
|
|
470
|
+
await this.checkBalance(totalInToken.mul(new BN(4)), balancePrefetch, abortController.signal)
|
|
448
471
|
metadata.times.balanceChecked = Date.now();
|
|
449
472
|
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
473
|
+
const blockHeight = await this.bitcoin.getBlockheight();
|
|
474
|
+
const feeRate = await this.bitcoin.getFeeRate();
|
|
475
|
+
const recommendedFee = Math.ceil(feeRate*this.config.recommendFeeMultiplier);
|
|
476
|
+
if(recommendedFee===0) throw {
|
|
477
|
+
_httpStatus: 500,
|
|
478
|
+
code: 21100,
|
|
479
|
+
msg: "Cannot estimate bitcoin fee!"
|
|
480
|
+
};
|
|
481
|
+
metadata.times.feeEstimated = Date.now();
|
|
482
|
+
|
|
483
|
+
const receiveAddress = await this.bitcoin.getAddress();
|
|
484
|
+
const outputScript = this.bitcoin.toOutputScript(receiveAddress).toString("hex");
|
|
454
485
|
abortController.signal.throwIfAborted();
|
|
455
486
|
metadata.times.addressCreated = Date.now();
|
|
456
487
|
|
|
457
|
-
const {current_block_height} = await getHeight({lnd: this.LND});
|
|
458
|
-
const feeRate = await this.config.feeEstimator.estimateFee();
|
|
459
|
-
const recommendedFee = Math.ceil(feeRate*this.config.recommendFeeMultiplier);
|
|
460
|
-
|
|
461
488
|
const createdSwap = new FromBtcTrustedSwap(
|
|
462
489
|
chainIdentifier,
|
|
463
490
|
swapFee,
|
|
@@ -466,17 +493,17 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
466
493
|
amountBD,
|
|
467
494
|
parsedBody.address,
|
|
468
495
|
totalInToken,
|
|
469
|
-
|
|
496
|
+
blockHeight,
|
|
470
497
|
Date.now()+(this.config.swapAddressExpiry*1000),
|
|
471
498
|
recommendedFee,
|
|
472
|
-
|
|
499
|
+
refundAddress
|
|
473
500
|
);
|
|
474
501
|
metadata.times.swapCreated = Date.now();
|
|
475
502
|
createdSwap.metadata = metadata;
|
|
476
503
|
|
|
477
504
|
await PluginManager.swapCreate(createdSwap);
|
|
478
|
-
await this.storageManager.saveData(createdSwap.getHash(),
|
|
479
|
-
this.subscriptions.set(
|
|
505
|
+
await this.storageManager.saveData(createdSwap.getHash(), createdSwap.getSequence(), createdSwap);
|
|
506
|
+
this.subscriptions.set(outputScript, createdSwap);
|
|
480
507
|
|
|
481
508
|
this.swapLogger.info(createdSwap, "REST: /getAddress: Created swap address: "+createdSwap.btcAddress+" amount: "+amountBD.toString(10));
|
|
482
509
|
|
|
@@ -485,6 +512,7 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
485
512
|
code: 10000,
|
|
486
513
|
data: {
|
|
487
514
|
paymentHash: createdSwap.getHash(),
|
|
515
|
+
sequence: createdSwap.getSequence().toString(10),
|
|
488
516
|
btcAddress: receiveAddress,
|
|
489
517
|
amountSats: amountBD.toString(10),
|
|
490
518
|
swapFeeSats: swapFee.toString(10),
|
|
@@ -496,27 +524,37 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
496
524
|
}
|
|
497
525
|
});
|
|
498
526
|
});
|
|
499
|
-
|
|
500
527
|
restServer.use(this.path+"/getAddress", serverParamDecoder(10*1000));
|
|
501
528
|
restServer.post(this.path+"/getAddress", getAddress);
|
|
502
529
|
|
|
503
530
|
const getInvoiceStatus = expressHandlerWrapper(async (req, res) => {
|
|
504
531
|
/**
|
|
505
532
|
* paymentHash: string payment hash of the invoice
|
|
533
|
+
* sequence: BN secret sequence for the swap,
|
|
506
534
|
*/
|
|
507
535
|
const parsedBody = verifySchema(req.query, {
|
|
508
536
|
paymentHash: (val: string) => val!=null &&
|
|
509
537
|
typeof(val)==="string" &&
|
|
510
538
|
val.length===64 &&
|
|
511
539
|
HEX_REGEX.test(val) ? val: null,
|
|
540
|
+
sequence: FieldTypeEnum.BN,
|
|
512
541
|
});
|
|
542
|
+
if(parsedBody==null) throw {
|
|
543
|
+
code: 20100,
|
|
544
|
+
msg: "Invalid request"
|
|
545
|
+
};
|
|
513
546
|
|
|
514
547
|
const processedTxData = this.processedTxIds.get(parsedBody.paymentHash);
|
|
515
548
|
if(processedTxData!=null) throw {
|
|
516
549
|
_httpStatus: 200,
|
|
517
550
|
code: 10000,
|
|
518
551
|
msg: "Success, tx confirmed",
|
|
519
|
-
data:
|
|
552
|
+
data: {
|
|
553
|
+
adjustedAmount: processedTxData.adjustedAmount.toString(10),
|
|
554
|
+
adjustedTotal: processedTxData.adjustedTotal.toString(10),
|
|
555
|
+
txId: processedTxData.txId,
|
|
556
|
+
scTxId: processedTxData.scTxId
|
|
557
|
+
}
|
|
520
558
|
};
|
|
521
559
|
|
|
522
560
|
const refundTxId = this.refundedSwaps.get(parsedBody.paymentHash);
|
|
@@ -539,7 +577,7 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
539
577
|
}
|
|
540
578
|
};
|
|
541
579
|
|
|
542
|
-
const invoiceData: FromBtcTrustedSwap = await this.storageManager.getData(parsedBody.paymentHash,
|
|
580
|
+
const invoiceData: FromBtcTrustedSwap = await this.storageManager.getData(parsedBody.paymentHash, parsedBody.sequence);
|
|
543
581
|
if (invoiceData==null) throw {
|
|
544
582
|
_httpStatus: 200,
|
|
545
583
|
code: 10001,
|
|
@@ -558,7 +596,8 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
558
596
|
msg: "Bitcoin received, payment processing",
|
|
559
597
|
data: {
|
|
560
598
|
adjustedAmount: invoiceData.adjustedInput.toString(10),
|
|
561
|
-
adjustedTotal: invoiceData.adjustedOutput.toString(10)
|
|
599
|
+
adjustedTotal: invoiceData.adjustedOutput.toString(10),
|
|
600
|
+
txId: invoiceData.txId
|
|
562
601
|
}
|
|
563
602
|
};
|
|
564
603
|
|
|
@@ -568,7 +607,8 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
568
607
|
msg: "Bitcoin accepted, payment processing",
|
|
569
608
|
data: {
|
|
570
609
|
adjustedAmount: invoiceData.adjustedInput.toString(10),
|
|
571
|
-
adjustedTotal: invoiceData.adjustedOutput.toString(10)
|
|
610
|
+
adjustedTotal: invoiceData.adjustedOutput.toString(10),
|
|
611
|
+
txId: invoiceData.txId
|
|
572
612
|
}
|
|
573
613
|
};
|
|
574
614
|
|
|
@@ -579,7 +619,8 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
579
619
|
data: {
|
|
580
620
|
adjustedAmount: invoiceData.adjustedInput.toString(10),
|
|
581
621
|
adjustedTotal: invoiceData.adjustedOutput.toString(10),
|
|
582
|
-
txId: invoiceData.
|
|
622
|
+
txId: invoiceData.txId,
|
|
623
|
+
scTxId: invoiceData.txIds.init
|
|
583
624
|
}
|
|
584
625
|
};
|
|
585
626
|
|
|
@@ -590,22 +631,83 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
590
631
|
data: {
|
|
591
632
|
adjustedAmount: invoiceData.adjustedInput.toString(10),
|
|
592
633
|
adjustedTotal: invoiceData.adjustedOutput.toString(10),
|
|
593
|
-
txId: invoiceData.
|
|
634
|
+
txId: invoiceData.txId,
|
|
635
|
+
scTxId: invoiceData.txIds.init
|
|
594
636
|
}
|
|
595
637
|
};
|
|
596
|
-
});
|
|
597
638
|
|
|
639
|
+
if (invoiceData.state === FromBtcTrustedSwapState.REFUNDABLE) throw {
|
|
640
|
+
_httpStatus: 200,
|
|
641
|
+
code: 10016,
|
|
642
|
+
msg: "Refundable",
|
|
643
|
+
data: {
|
|
644
|
+
adjustedAmount: invoiceData.adjustedInput.toString(10)
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
});
|
|
598
648
|
restServer.get(this.path+"/getAddressStatus", getInvoiceStatus);
|
|
599
649
|
|
|
650
|
+
const setRefundAddress = expressHandlerWrapper(async (req, res) => {
|
|
651
|
+
/**
|
|
652
|
+
* paymentHash: string payment hash of the invoice
|
|
653
|
+
* sequence: BN secret sequence for the swap,
|
|
654
|
+
* refundAddress: string valid bitcoin address to be used for refunds
|
|
655
|
+
*/
|
|
656
|
+
const parsedBody = verifySchema({...req.body, ...req.query}, {
|
|
657
|
+
paymentHash: (val: string) => val!=null &&
|
|
658
|
+
typeof(val)==="string" &&
|
|
659
|
+
val.length===64 &&
|
|
660
|
+
HEX_REGEX.test(val) ? val: null,
|
|
661
|
+
sequence: FieldTypeEnum.BN,
|
|
662
|
+
refundAddress: (val: string) => val!=null &&
|
|
663
|
+
typeof(val)==="string" &&
|
|
664
|
+
this.isValidBitcoinAddress(val) ? val : null
|
|
665
|
+
});
|
|
666
|
+
if(parsedBody==null) throw {
|
|
667
|
+
code: 20100,
|
|
668
|
+
msg: "Invalid request"
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const invoiceData: FromBtcTrustedSwap = await this.storageManager.getData(parsedBody.paymentHash, null);
|
|
672
|
+
if (invoiceData==null || !invoiceData.getSequence().eq(parsedBody.sequence)) throw {
|
|
673
|
+
code: 10001,
|
|
674
|
+
msg: "Swap not found"
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
if(invoiceData.refundAddress!=null) throw {
|
|
678
|
+
code: 10080,
|
|
679
|
+
msg: "Refund address already set!",
|
|
680
|
+
data: {
|
|
681
|
+
refundAddress: invoiceData.refundAddress
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
invoiceData.refundAddress = parsedBody.refundAddress;
|
|
686
|
+
|
|
687
|
+
if (invoiceData.state === FromBtcTrustedSwapState.REFUNDABLE) {
|
|
688
|
+
this.refundSwap(invoiceData).catch(e => {
|
|
689
|
+
this.swapLogger.error(invoiceData, "/setRefundAddress: Failed to refund!");
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
throw {
|
|
694
|
+
_httpStatus: 200,
|
|
695
|
+
code: 10000,
|
|
696
|
+
msg: "Refund address set"
|
|
697
|
+
};
|
|
698
|
+
});
|
|
699
|
+
restServer.get(this.path+"/setRefundAddress", setRefundAddress);
|
|
700
|
+
restServer.post(this.path+"/setRefundAddress", setRefundAddress);
|
|
701
|
+
|
|
600
702
|
this.logger.info("started at path: ", this.path);
|
|
601
703
|
}
|
|
602
704
|
|
|
603
705
|
private async checkDoubleSpends(): Promise<void> {
|
|
604
706
|
for(let swap of this.doubleSpendWatchdogSwaps.keys()) {
|
|
605
|
-
const tx = await this.
|
|
707
|
+
const tx = await this.bitcoin.getWalletTransaction(swap.txId);
|
|
606
708
|
if(tx==null) {
|
|
607
709
|
this.swapLogger.debug(swap, "checkDoubleSpends(): Swap was double spent, burning... - original txId: "+swap.txId);
|
|
608
|
-
this.processPastSwap(swap, null);
|
|
710
|
+
this.processPastSwap(swap, null, null);
|
|
609
711
|
}
|
|
610
712
|
}
|
|
611
713
|
}
|
|
@@ -620,12 +722,11 @@ export class FromBtcTrusted extends FromBtcBaseSwapHandler<FromBtcTrustedSwap, F
|
|
|
620
722
|
}
|
|
621
723
|
|
|
622
724
|
private listenToTxns() {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
const savedSwap = this.subscriptions.get(address);
|
|
725
|
+
this.bitcoin.subscribeToWalletTransactions((btcTx: BtcTx) => {
|
|
726
|
+
for(let out of btcTx.outs) {
|
|
727
|
+
const savedSwap = this.subscriptions.get(out.scriptPubKey.hex);
|
|
627
728
|
if(savedSwap==null) continue;
|
|
628
|
-
this.processPastSwap(savedSwap,
|
|
729
|
+
this.processPastSwap(savedSwap, btcTx, out.n);
|
|
629
730
|
return;
|
|
630
731
|
}
|
|
631
732
|
});
|