@atomiqlabs/lp-lib 10.3.11 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +2 -4
  3. package/dist/plugins/IPlugin.d.ts +3 -2
  4. package/dist/plugins/PluginManager.d.ts +3 -2
  5. package/dist/plugins/PluginManager.js +2 -2
  6. package/dist/swaps/FromBtcBaseSwap.d.ts +5 -1
  7. package/dist/swaps/FromBtcBaseSwap.js +20 -0
  8. package/dist/swaps/FromBtcBaseSwapHandler.d.ts +1 -0
  9. package/dist/swaps/FromBtcBaseSwapHandler.js +1 -1
  10. package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +8 -6
  11. package/dist/swaps/FromBtcLnBaseSwapHandler.js +7 -5
  12. package/dist/swaps/SwapHandler.d.ts +1 -4
  13. package/dist/swaps/SwapHandler.js +1 -2
  14. package/dist/swaps/SwapHandlerSwap.d.ts +4 -0
  15. package/dist/swaps/SwapHandlerSwap.js +9 -1
  16. package/dist/swaps/ToBtcBaseSwap.d.ts +3 -1
  17. package/dist/swaps/ToBtcBaseSwap.js +8 -2
  18. package/dist/swaps/ToBtcBaseSwapHandler.d.ts +1 -0
  19. package/dist/swaps/ToBtcBaseSwapHandler.js +1 -1
  20. package/dist/swaps/frombtc_abstract/FromBtcAbs.d.ts +3 -5
  21. package/dist/swaps/frombtc_abstract/FromBtcAbs.js +18 -25
  22. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.d.ts +1 -4
  23. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.js +3 -16
  24. package/dist/swaps/frombtc_trusted/FromBtcTrusted.d.ts +6 -9
  25. package/dist/swaps/frombtc_trusted/FromBtcTrusted.js +238 -137
  26. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.d.ts +9 -6
  27. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.js +15 -10
  28. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.d.ts +2 -2
  29. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.js +42 -62
  30. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +1 -6
  31. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.js +2 -14
  32. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.d.ts +3 -5
  33. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.js +64 -80
  34. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.d.ts +1 -2
  35. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.js +5 -8
  36. package/dist/swaps/tobtc_abstract/ToBtcAbs.d.ts +5 -125
  37. package/dist/swaps/tobtc_abstract/ToBtcAbs.js +41 -334
  38. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.d.ts +1 -4
  39. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.js +2 -11
  40. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.d.ts +5 -55
  41. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.js +152 -398
  42. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.d.ts +1 -6
  43. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.js +2 -15
  44. package/dist/utils/Utils.d.ts +0 -10
  45. package/dist/utils/Utils.js +1 -34
  46. package/dist/wallets/IBitcoinWallet.d.ts +62 -0
  47. package/dist/wallets/IBitcoinWallet.js +2 -0
  48. package/dist/wallets/ILightningWallet.d.ts +118 -0
  49. package/dist/wallets/ILightningWallet.js +37 -0
  50. package/package.json +4 -9
  51. package/src/index.ts +3 -5
  52. package/src/plugins/IPlugin.ts +4 -2
  53. package/src/plugins/PluginManager.ts +6 -3
  54. package/src/swaps/FromBtcBaseSwap.ts +24 -1
  55. package/src/swaps/FromBtcBaseSwapHandler.ts +6 -2
  56. package/src/swaps/FromBtcLnBaseSwapHandler.ts +22 -6
  57. package/src/swaps/SwapHandler.ts +1 -8
  58. package/src/swaps/SwapHandlerSwap.ts +14 -1
  59. package/src/swaps/ToBtcBaseSwap.ts +12 -3
  60. package/src/swaps/ToBtcBaseSwapHandler.ts +6 -2
  61. package/src/swaps/frombtc_abstract/FromBtcAbs.ts +24 -28
  62. package/src/swaps/frombtc_abstract/FromBtcSwapAbs.ts +3 -18
  63. package/src/swaps/frombtc_trusted/FromBtcTrusted.ts +260 -159
  64. package/src/swaps/frombtc_trusted/FromBtcTrustedSwap.ts +22 -15
  65. package/src/swaps/frombtcln_abstract/FromBtcLnAbs.ts +69 -79
  66. package/src/swaps/frombtcln_abstract/FromBtcLnSwapAbs.ts +3 -20
  67. package/src/swaps/frombtcln_trusted/FromBtcLnTrusted.ts +80 -97
  68. package/src/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.ts +6 -9
  69. package/src/swaps/tobtc_abstract/ToBtcAbs.ts +52 -410
  70. package/src/swaps/tobtc_abstract/ToBtcSwapAbs.ts +3 -18
  71. package/src/swaps/tobtcln_abstract/ToBtcLnAbs.ts +157 -434
  72. package/src/swaps/tobtcln_abstract/ToBtcLnSwapAbs.ts +3 -20
  73. package/src/utils/Utils.ts +0 -31
  74. package/src/wallets/IBitcoinWallet.ts +66 -0
  75. package/src/wallets/ILightningWallet.ts +179 -0
  76. package/dist/fees/OneDollarFeeEstimator.d.ts +0 -16
  77. package/dist/fees/OneDollarFeeEstimator.js +0 -71
  78. package/dist/utils/coinselect2/accumulative.d.ts +0 -6
  79. package/dist/utils/coinselect2/accumulative.js +0 -44
  80. package/dist/utils/coinselect2/blackjack.d.ts +0 -6
  81. package/dist/utils/coinselect2/blackjack.js +0 -41
  82. package/dist/utils/coinselect2/index.d.ts +0 -16
  83. package/dist/utils/coinselect2/index.js +0 -40
  84. package/dist/utils/coinselect2/utils.d.ts +0 -64
  85. package/dist/utils/coinselect2/utils.js +0 -121
  86. package/src/fees/OneDollarFeeEstimator.ts +0 -95
  87. package/src/utils/coinselect2/accumulative.js +0 -32
  88. package/src/utils/coinselect2/accumulative.ts +0 -58
  89. package/src/utils/coinselect2/blackjack.js +0 -29
  90. package/src/utils/coinselect2/blackjack.ts +0 -54
  91. package/src/utils/coinselect2/index.js +0 -16
  92. package/src/utils/coinselect2/index.ts +0 -50
  93. package/src/utils/coinselect2/utils.js +0 -110
  94. package/src/utils/coinselect2/utils.ts +0 -183
@@ -1,5 +1,4 @@
1
1
  import * as BN from "bn.js";
2
- import * as bolt11 from "@atomiqlabs/bolt11";
3
2
  import {SwapData} from "@atomiqlabs/base";
4
3
  import {SwapHandlerType} from "../..";
5
4
  import {deserializeBN, serializeBN} from "../../utils/Utils";
@@ -18,31 +17,28 @@ export enum ToBtcLnSwapState {
18
17
  export class ToBtcLnSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap<T, ToBtcLnSwapState> {
19
18
 
20
19
  readonly pr: string;
21
- readonly signatureExpiry: BN;
22
20
 
23
21
  secret: string;
24
22
 
25
23
  constructor(
26
24
  chainIdentifier: string,
27
25
  pr: string,
26
+ amountMtokens: BN,
28
27
  swapFee: BN,
29
28
  swapFeeInToken: BN,
30
29
  quotedNetworkFee: BN,
31
30
  quotedNetworkFeeInToken: BN,
32
- signatureExpiry: BN
33
31
  );
34
32
  constructor(obj: any);
35
33
 
36
- constructor(chainIdOrObj: string | any, pr?: string, swapFee?: BN, swapFeeInToken?: BN, quotedNetworkFee?: BN, quotedNetworkFeeInToken?: BN, signatureExpiry?: BN) {
34
+ constructor(chainIdOrObj: string | any, pr?: string, amount?: BN, swapFee?: BN, swapFeeInToken?: BN, quotedNetworkFee?: BN, quotedNetworkFeeInToken?: BN) {
37
35
  if(typeof(chainIdOrObj)==="string") {
38
- super(chainIdOrObj, swapFee, swapFeeInToken, quotedNetworkFee, quotedNetworkFeeInToken);
36
+ super(chainIdOrObj, amount.add(new BN(999)).div(new BN(1000)), swapFee, swapFeeInToken, quotedNetworkFee, quotedNetworkFeeInToken);
39
37
  this.state = ToBtcLnSwapState.SAVED;
40
38
  this.pr = pr;
41
- this.signatureExpiry = signatureExpiry;
42
39
  } else {
43
40
  super(chainIdOrObj);
44
41
  this.pr = chainIdOrObj.pr;
45
- this.signatureExpiry = deserializeBN(chainIdOrObj.signatureExpiry);
46
42
  this.secret = chainIdOrObj.secret;
47
43
 
48
44
  //Compatibility with older versions
@@ -55,19 +51,10 @@ export class ToBtcLnSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap
55
51
  serialize(): any {
56
52
  const partialSerialized = super.serialize();
57
53
  partialSerialized.pr = this.pr;
58
- partialSerialized.signatureExpiry = serializeBN(this.signatureExpiry);
59
54
  partialSerialized.secret = this.secret;
60
55
  return partialSerialized;
61
56
  }
62
57
 
63
- getHash(): string {
64
- return bolt11.decode(this.pr).tagsObject.payment_hash;
65
- }
66
-
67
- getHashBuffer(): Buffer {
68
- return Buffer.from(bolt11.decode(this.pr).tagsObject.payment_hash, "hex");
69
- }
70
-
71
58
  isInitiated(): boolean {
72
59
  return this.state!==ToBtcLnSwapState.SAVED;
73
60
  }
@@ -80,8 +67,4 @@ export class ToBtcLnSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap
80
67
  return this.state===ToBtcLnSwapState.CLAIMED;
81
68
  }
82
69
 
83
- getOutputAmount(): BN {
84
- return new BN(bolt11.decode(this.pr).millisatoshis).add(new BN(999)).div(new BN(1000));
85
- }
86
-
87
70
  }
@@ -68,22 +68,6 @@ export function getLogger(prefix: string) {
68
68
 
69
69
  export const HEX_REGEX = /[0-9a-fA-F]+/;
70
70
 
71
- export function shuffle(array: any[]) {
72
- let currentIndex = array.length;
73
-
74
- // While there remain elements to shuffle...
75
- while (currentIndex != 0) {
76
-
77
- // Pick a remaining element...
78
- let randomIndex = Math.floor(Math.random() * currentIndex);
79
- currentIndex--;
80
-
81
- // And swap it with the current element.
82
- [array[currentIndex], array[randomIndex]] = [
83
- array[randomIndex], array[currentIndex]];
84
- }
85
- }
86
-
87
71
  export function serializeBN(bn: BN | null): string | null {
88
72
  return bn==null ? null : bn.toString(10);
89
73
  }
@@ -91,18 +75,3 @@ export function serializeBN(bn: BN | null): string | null {
91
75
  export function deserializeBN(str: string | null): BN | null {
92
76
  return str==null ? null : new BN(str);
93
77
  }
94
-
95
- /**
96
- * Handles & throws LND error if the error is:
97
- * - network error
98
- * - server side (LND) internal error
99
- * - malformed input data error
100
- *
101
- * @param e
102
- */
103
- export function handleLndError(e: any) {
104
- if(!Array.isArray(e)) throw e; //Throw errors that are not originating from the SDK
105
- if(typeof(e[0])!=="number") throw e; //Throw errors that don't have proper format
106
- if(e[0]>=500 && e[0]<600) throw e; //Throw server errors 5xx
107
- if(e[0]===400) throw e; //Throw malformed request data errors
108
- }
@@ -0,0 +1,66 @@
1
+ import BN from "bn.js";
2
+ import {Psbt, Transaction} from "bitcoinjs-lib";
3
+ import {BtcTx} from "@atomiqlabs/base";
4
+ import {Command} from "@atomiqlabs/server-base";
5
+
6
+ export type BitcoinUtxo = {
7
+ address: string,
8
+ type: "p2wpkh" | "p2sh-p2wpkh" | "p2tr",
9
+ confirmations: number,
10
+ outputScript: Buffer,
11
+ value: number,
12
+ txId: string,
13
+ vout: number
14
+ };
15
+
16
+ export type SignPsbtResponse = {
17
+ psbt: Psbt,
18
+ tx: Transaction,
19
+ raw: string,
20
+ txId: string,
21
+ networkFee: number
22
+ };
23
+
24
+ export interface IBitcoinWallet {
25
+
26
+ init(): Promise<void>;
27
+
28
+ isReady(): boolean;
29
+ getStatus(): string;
30
+ getStatusInfo(): Promise<Record<string, string>>;
31
+ getCommands(): Command<any>[];
32
+
33
+ toOutputScript(address: string): Buffer;
34
+
35
+ getAddressType(): "p2wpkh" | "p2sh-p2wpkh" | "p2tr";
36
+ /**
37
+ * Returns an unused address suitable for receiving
38
+ */
39
+ getAddress(): Promise<string>;
40
+ /**
41
+ * Adds previously returned address (with getAddress call), to the pool of unused addresses
42
+ * @param address
43
+ */
44
+ addUnusedAddress(address: string): Promise<void>;
45
+
46
+ getUtxos(): Promise<BitcoinUtxo[]>;
47
+ getBalance(): Promise<{confirmed: number, unconfirmed: number}>;
48
+ /**
49
+ * Returns required reserve amount that needs to be kept in the wallet (for e.g. lightning anchor channels)
50
+ */
51
+ getRequiredReserve(): Promise<number>;
52
+ getWalletTransactions(startHeight?: number): Promise<BtcTx[]>;
53
+ getWalletTransaction(txId: string): Promise<BtcTx | null>;
54
+ subscribeToWalletTransactions(callback: (tx: BtcTx) => void, abortSignal?: AbortSignal): void;
55
+
56
+ signPsbt(psbt: Psbt): Promise<SignPsbtResponse>;
57
+ sendRawTransaction(tx: string): Promise<void>;
58
+ getSignedTransaction(destination: string, amount: number, feeRate?: number, nonce?: BN, maxAllowedFeeRate?: number): Promise<SignPsbtResponse>;
59
+ estimateFee(destination: string, amount: number, feeRate?: number, feeRateMultiplier?: number): Promise<{satsPerVbyte: number, networkFee: number}>;
60
+ drainAll(destination: string | Buffer, inputs: Omit<BitcoinUtxo, "address">[], feeRate?: number): Promise<SignPsbtResponse>;
61
+ burnAll(inputs: Omit<BitcoinUtxo, "address">[]): Promise<SignPsbtResponse>;
62
+
63
+ getBlockheight(): Promise<number>;
64
+ getFeeRate(): Promise<number>;
65
+
66
+ }
@@ -0,0 +1,179 @@
1
+ import * as BN from "bn.js";
2
+ import {Command} from "@atomiqlabs/server-base";
3
+
4
+ export type IncomingLightningNetworkPayment = {
5
+ createdAt: number,
6
+ confirmedAt: number,
7
+
8
+ createdHeight: number,
9
+ timeout: number,
10
+
11
+ status: "held" | "canceled" | "confirmed"
12
+
13
+ mtokens: BN
14
+ }
15
+
16
+ export type LightningNetworkInvoice = {
17
+ id: string,
18
+ request: string,
19
+ secret?: string,
20
+
21
+ cltvDelta: number,
22
+ mtokens: BN,
23
+
24
+ createdAt: number,
25
+ expiresAt: number,
26
+
27
+ description: string,
28
+ descriptionHash?: string,
29
+
30
+ payments: IncomingLightningNetworkPayment[],
31
+
32
+ status: "unpaid" | "held" | "canceled" | "confirmed"
33
+ };
34
+
35
+ export type OutgoingLightningNetworkPayment = {
36
+ failedReason?: "insufficient_balance" | "invalid_payment" | "pathfinding_timeout" | "route_not_found",
37
+ status: "confirmed" | "failed" | "pending",
38
+ secret?: string,
39
+ feeMtokens?: BN
40
+ };
41
+
42
+ export type LightningNetworkChannel = {
43
+ id: string,
44
+ capacity: BN,
45
+ isActive: boolean,
46
+
47
+ localBalance: BN,
48
+ localReserve: BN,
49
+ remoteBalance: BN,
50
+ remoteReserve: BN,
51
+ unsettledBalance: BN,
52
+ transactionId: string,
53
+ transactionVout: number
54
+ };
55
+
56
+ export type InvoiceInit = {
57
+ mtokens: BN,
58
+ descriptionHash?: string
59
+ description?: string,
60
+ cltvDelta?: number,
61
+ expiresAt?: number,
62
+ };
63
+
64
+ export type HodlInvoiceInit = {
65
+ description: string,
66
+ cltvDelta: number,
67
+ expiresAt: number,
68
+ id: string,
69
+ mtokens: BN,
70
+ descriptionHash?: string
71
+ };
72
+
73
+ export type LNRoutes = {
74
+ publicKey: string,
75
+ feeRate?: number,
76
+ cltvDelta?: number,
77
+ channel?: string,
78
+ baseFeeMtokens?: BN
79
+ }[][];
80
+
81
+ export type ParsedPaymentRequest = {
82
+ id: string,
83
+ mtokens: BN,
84
+ expiryEpochMillis: number,
85
+ destination: string,
86
+ cltvDelta: number,
87
+ description: string,
88
+ routes: LNRoutes
89
+ };
90
+
91
+ export type LightningPaymentInit = {
92
+ request: string,
93
+ maxFeeMtokens?: BN,
94
+ maxTimeoutHeight?: number
95
+ };
96
+
97
+ export type LightningBalanceResponse = {
98
+ localBalance: BN,
99
+ remoteBalance: BN,
100
+ unsettledBalance: BN
101
+ };
102
+
103
+ export type ProbeAndRouteInit = {
104
+ request: string,
105
+ amountMtokens: BN,
106
+ maxFeeMtokens: BN,
107
+ maxTimeoutHeight: number
108
+ }
109
+
110
+ export type ProbeAndRouteResponse = {
111
+ confidence: number,
112
+ feeMtokens: BN,
113
+ destination: string,
114
+ privateRoutes: LNRoutes
115
+ }
116
+
117
+ export function routesMatch(routesA: LNRoutes, routesB: LNRoutes) {
118
+ if(routesA===routesB) return true;
119
+ if(routesA==null || routesB==null) {
120
+ return false;
121
+ }
122
+ if(routesA.length!==routesB.length) return false;
123
+ for(let i=0;i<routesA.length;i++) {
124
+ if(routesA[i]===routesB[i]) continue;
125
+ if(routesA[i]==null || routesB[i]==null) {
126
+ return false;
127
+ }
128
+ if(routesA[i].length!==routesB[i].length) return false;
129
+ for(let e=0;e<routesA[i].length;e++) {
130
+ if(routesA[i][e]===routesB[i][e]) continue;
131
+ if(routesA[i][e]==null || routesB[i][e]==null) {
132
+ return false;
133
+ }
134
+ if(
135
+ routesA[i][e].publicKey!==routesB[i][e].publicKey ||
136
+ !routesA[i][e].baseFeeMtokens.eq(routesB[i][e].baseFeeMtokens) ||
137
+ routesA[i][e].channel!==routesB[i][e].channel ||
138
+ routesA[i][e].cltvDelta!==routesB[i][e].cltvDelta ||
139
+ routesA[i][e].feeRate!==routesB[i][e].feeRate
140
+ ) {
141
+ return false;
142
+ }
143
+ }
144
+ }
145
+
146
+ return true;
147
+ }
148
+
149
+ export interface ILightningWallet {
150
+
151
+ init(): Promise<void>;
152
+
153
+ isReady(): boolean;
154
+ getStatus(): string;
155
+ getStatusInfo(): Promise<Record<string, string>>;
156
+ getCommands(): Command<any>[];
157
+
158
+ createInvoice(init: InvoiceInit): Promise<LightningNetworkInvoice>;
159
+ createHodlInvoice(init: HodlInvoiceInit): Promise<LightningNetworkInvoice>;
160
+ getInvoice(paymentHash: string): Promise<LightningNetworkInvoice | null>;
161
+ cancelHodlInvoice(paymentHash: string): Promise<void>;
162
+ settleHodlInvoice(secret: string): Promise<void>;
163
+ waitForInvoice(paymentHash: string, abortSignal?: AbortSignal): Promise<LightningNetworkInvoice>;
164
+
165
+ pay(init: LightningPaymentInit): Promise<void>;
166
+ getPayment(paymentHash: string): Promise<OutgoingLightningNetworkPayment | null>
167
+ waitForPayment(paymentHash: string, abortSignal?: AbortSignal): Promise<OutgoingLightningNetworkPayment>;
168
+ probe(init: ProbeAndRouteInit): Promise<ProbeAndRouteResponse | null>;
169
+ route(init: ProbeAndRouteInit): Promise<ProbeAndRouteResponse | null>;
170
+
171
+ parsePaymentRequest(request: string): Promise<ParsedPaymentRequest>;
172
+
173
+ getBlockheight(): Promise<number>;
174
+ getChannels(activeOnly?: boolean): Promise<LightningNetworkChannel[]>;
175
+ getLightningBalance(): Promise<LightningBalanceResponse>;
176
+
177
+ getIdentityPublicKey(): Promise<string>;
178
+
179
+ }
@@ -1,16 +0,0 @@
1
- import { IBtcFeeEstimator } from "./IBtcFeeEstimator";
2
- export declare class OneDollarFeeEstimator implements IBtcFeeEstimator {
3
- estimator: any;
4
- receivedFee: [number, number, number, number];
5
- iterations: number;
6
- host: string;
7
- port: number;
8
- username: string;
9
- password: string;
10
- addFee: number;
11
- feeMultiplier: number;
12
- startFeeEstimator(): void;
13
- constructor(host: string, port: number, username: string, password: string, addFee?: number, feeMultiplier?: number);
14
- getFee(): number;
15
- estimateFee(): Promise<number | null>;
16
- }
@@ -1,71 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OneDollarFeeEstimator = void 0;
4
- const Utils_1 = require("../utils/Utils");
5
- const dynamicImport = new Function('specifier', 'return import(specifier)');
6
- const importPromise = dynamicImport('one-dollar-fee-estimator-failover');
7
- const logger = (0, Utils_1.getLogger)("OneDollarFeeEstimator: ");
8
- class OneDollarFeeEstimator {
9
- startFeeEstimator() {
10
- logger.info("startFeeEstimator(): starting fee estimator worker");
11
- importPromise.then(({ FeeEstimator }) => {
12
- this.estimator = new FeeEstimator({
13
- mode: 'bundles',
14
- refresh: 30,
15
- rpcOptions: {
16
- host: this.host,
17
- port: this.port,
18
- username: this.username,
19
- password: this.password
20
- }
21
- });
22
- this.estimator.on('error', (err) => {
23
- logger.error("on(error): fee estimator error", err);
24
- if (err.message.startsWith("FeeEstimator worker stopped")) {
25
- logger.info("on(error): restarting fee estimator worker");
26
- this.receivedFee = null;
27
- this.iterations = 0;
28
- this.startFeeEstimator();
29
- }
30
- });
31
- // receive live fee rate updates from the FeeEstimator
32
- this.estimator.on('fees', (fees) => {
33
- this.receivedFee = fees;
34
- this.iterations++;
35
- });
36
- });
37
- }
38
- constructor(host, port, username, password, addFee, feeMultiplier) {
39
- this.iterations = 0;
40
- this.host = host;
41
- this.port = port;
42
- this.username = username;
43
- this.password = password;
44
- this.addFee = addFee;
45
- this.feeMultiplier = feeMultiplier;
46
- this.startFeeEstimator();
47
- process.on('exit', () => {
48
- logger.info("process(exit): process exiting, stopping estimator");
49
- if (this.estimator != null)
50
- this.estimator.stop();
51
- });
52
- process.on('SIGINT', () => {
53
- logger.info("process(SIGINT): process exiting, stopping estimator");
54
- if (this.estimator != null)
55
- this.estimator.stop();
56
- process.exit();
57
- });
58
- }
59
- getFee() {
60
- let fee = this.receivedFee[3];
61
- if (this.feeMultiplier != null)
62
- fee *= this.feeMultiplier;
63
- if (this.addFee != null)
64
- fee += this.addFee;
65
- return fee;
66
- }
67
- estimateFee() {
68
- return Promise.resolve(this.iterations <= 1 ? null : this.getFee());
69
- }
70
- }
71
- exports.OneDollarFeeEstimator = OneDollarFeeEstimator;
@@ -1,6 +0,0 @@
1
- import { CoinselectAddressTypes, CoinselectTxInput, CoinselectTxOutput } from "./utils";
2
- export declare function accumulative(utxos: CoinselectTxInput[], outputs: CoinselectTxOutput[], feeRate: number, type: CoinselectAddressTypes, requiredInputs?: CoinselectTxInput[]): {
3
- inputs?: CoinselectTxInput[];
4
- outputs?: CoinselectTxOutput[];
5
- fee: number;
6
- };
@@ -1,44 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.accumulative = void 0;
4
- const utils_1 = require("./utils");
5
- // add inputs until we reach or surpass the target value (or deplete)
6
- // worst-case: O(n)
7
- function accumulative(utxos, outputs, feeRate, type, requiredInputs) {
8
- if (!isFinite(utils_1.utils.uintOrNaN(feeRate)))
9
- return null;
10
- let bytesAccum = utils_1.utils.transactionBytes([], outputs, type);
11
- let inAccum = 0;
12
- const inputs = [];
13
- if (requiredInputs != null)
14
- for (let utxo of requiredInputs) {
15
- const { length: utxoBytes } = utils_1.utils.inputBytes(utxo);
16
- const utxoValue = utils_1.utils.uintOrNaN(utxo.value);
17
- bytesAccum += utxoBytes;
18
- inAccum += utxoValue;
19
- inputs.push(utxo);
20
- }
21
- const outAccum = utils_1.utils.sumOrNaN(outputs);
22
- for (let i = 0; i < utxos.length; ++i) {
23
- const utxo = utxos[i];
24
- const { length: utxoBytes } = utils_1.utils.inputBytes(utxo);
25
- const utxoFee = feeRate * utxoBytes;
26
- const utxoValue = utils_1.utils.uintOrNaN(utxo.value);
27
- // skip detrimental input
28
- if (utxoFee > utxo.value) {
29
- if (i === utxos.length - 1)
30
- return { fee: feeRate * (bytesAccum + utxoBytes) };
31
- continue;
32
- }
33
- bytesAccum += utxoBytes;
34
- inAccum += utxoValue;
35
- inputs.push(utxo);
36
- const fee = feeRate * bytesAccum;
37
- // go again?
38
- if (inAccum < outAccum + fee)
39
- continue;
40
- return utils_1.utils.finalize(inputs, outputs, feeRate, type);
41
- }
42
- return { fee: feeRate * bytesAccum };
43
- }
44
- exports.accumulative = accumulative;
@@ -1,6 +0,0 @@
1
- import { CoinselectAddressTypes, CoinselectTxInput, CoinselectTxOutput } from "./utils";
2
- export declare function blackjack(utxos: CoinselectTxInput[], outputs: CoinselectTxOutput[], feeRate: number, type: CoinselectAddressTypes, requiredInputs?: CoinselectTxInput[]): {
3
- inputs?: CoinselectTxInput[];
4
- outputs?: CoinselectTxOutput[];
5
- fee: number;
6
- };
@@ -1,41 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.blackjack = void 0;
4
- const utils_1 = require("./utils");
5
- // add inputs until we reach or surpass the target value (or deplete)
6
- // worst-case: O(n)
7
- function blackjack(utxos, outputs, feeRate, type, requiredInputs) {
8
- if (!isFinite(utils_1.utils.uintOrNaN(feeRate)))
9
- return null;
10
- let bytesAccum = utils_1.utils.transactionBytes([], outputs, type);
11
- let inAccum = 0;
12
- const inputs = [];
13
- if (requiredInputs != null)
14
- for (let utxo of requiredInputs) {
15
- const { length: utxoBytes } = utils_1.utils.inputBytes(utxo);
16
- const utxoValue = utils_1.utils.uintOrNaN(utxo.value);
17
- bytesAccum += utxoBytes;
18
- inAccum += utxoValue;
19
- inputs.push(utxo);
20
- }
21
- const outAccum = utils_1.utils.sumOrNaN(outputs);
22
- const threshold = utils_1.utils.dustThreshold({ type });
23
- for (let i = 0; i < utxos.length; ++i) {
24
- const input = utxos[i];
25
- const { length: inputBytes } = utils_1.utils.inputBytes(input);
26
- const fee = feeRate * (bytesAccum + inputBytes);
27
- const inputValue = utils_1.utils.uintOrNaN(input.value);
28
- // would it waste value?
29
- if ((inAccum + inputValue) > (outAccum + fee + threshold))
30
- continue;
31
- bytesAccum += inputBytes;
32
- inAccum += inputValue;
33
- inputs.push(input);
34
- // go again?
35
- if (inAccum < outAccum + fee)
36
- continue;
37
- return utils_1.utils.finalize(inputs, outputs, feeRate, type);
38
- }
39
- return { fee: feeRate * bytesAccum };
40
- }
41
- exports.blackjack = blackjack;
@@ -1,16 +0,0 @@
1
- import { CoinselectAddressTypes, CoinselectTxInput, CoinselectTxOutput } from "./utils";
2
- /**
3
- * Runs a coinselection algorithm on given inputs, outputs and fee rate
4
- *
5
- * @param utxos Utxo pool to select additional inputs from
6
- * @param outputs Outputs of the transaction
7
- * @param feeRate Feerate in sats/vB
8
- * @param changeType Change address type
9
- * @param requiredInputs Utxos that need to be included as inputs to the transaction
10
- * @param randomize Randomize the UTXO order before running the coinselection algorithm
11
- */
12
- export declare function coinSelect(utxos: CoinselectTxInput[], outputs: CoinselectTxOutput[], feeRate: number, changeType: CoinselectAddressTypes, requiredInputs?: CoinselectTxInput[], randomize?: boolean): {
13
- inputs?: CoinselectTxInput[];
14
- outputs?: CoinselectTxOutput[];
15
- fee: number;
16
- };
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.coinSelect = void 0;
4
- const accumulative_1 = require("./accumulative");
5
- const blackjack_1 = require("./blackjack");
6
- const utils_1 = require("./utils");
7
- const BN = require("bn.js");
8
- const Utils_1 = require("../Utils");
9
- // order by descending value, minus the inputs approximate fee
10
- function utxoScore(x, feeRate) {
11
- return x.value - (feeRate * utils_1.utils.inputBytes(x).length);
12
- }
13
- function utxoFeePPM(utxo, feeRate) {
14
- return new BN(utxo.value).mul(new BN(1000000)).div(new BN(Math.ceil(feeRate * utils_1.utils.inputBytes(utxo).length))).toNumber();
15
- }
16
- /**
17
- * Runs a coinselection algorithm on given inputs, outputs and fee rate
18
- *
19
- * @param utxos Utxo pool to select additional inputs from
20
- * @param outputs Outputs of the transaction
21
- * @param feeRate Feerate in sats/vB
22
- * @param changeType Change address type
23
- * @param requiredInputs Utxos that need to be included as inputs to the transaction
24
- * @param randomize Randomize the UTXO order before running the coinselection algorithm
25
- */
26
- function coinSelect(utxos, outputs, feeRate, changeType, requiredInputs, randomize) {
27
- if (randomize) {
28
- (0, Utils_1.shuffle)(utxos);
29
- }
30
- else {
31
- utxos.sort((a, b) => utxoScore(b, feeRate) - utxoScore(a, feeRate));
32
- }
33
- // attempt to use the blackjack strategy first (no change output)
34
- let base = (0, blackjack_1.blackjack)(utxos, outputs, feeRate, changeType, requiredInputs);
35
- if (base.inputs)
36
- return base;
37
- // else, try the accumulative strategy
38
- return (0, accumulative_1.accumulative)(utxos, outputs, feeRate, changeType, requiredInputs);
39
- }
40
- exports.coinSelect = coinSelect;
@@ -1,64 +0,0 @@
1
- /// <reference types="node" />
2
- export type CoinselectAddressTypes = "p2sh-p2wpkh" | "p2wpkh" | "p2wsh" | "p2tr" | "p2pkh";
3
- export type CoinselectTxInput = {
4
- script?: Buffer;
5
- witness?: Buffer;
6
- txId: string;
7
- vout: number;
8
- type?: CoinselectAddressTypes;
9
- value: number;
10
- outputScript?: Buffer;
11
- address?: string;
12
- };
13
- export type CoinselectTxOutput = {
14
- script?: Buffer;
15
- address?: string;
16
- type?: CoinselectAddressTypes;
17
- value: number;
18
- };
19
- declare function inputBytes(input: {
20
- script?: Buffer;
21
- witness?: Buffer;
22
- type?: CoinselectAddressTypes;
23
- }): {
24
- length: number;
25
- isWitness: boolean;
26
- };
27
- declare function outputBytes(output: {
28
- script?: Buffer;
29
- type?: CoinselectAddressTypes;
30
- }): number;
31
- declare function dustThreshold(output: {
32
- script?: Buffer;
33
- type: CoinselectAddressTypes;
34
- }): number;
35
- declare function transactionBytes(inputs: {
36
- script?: Buffer;
37
- type?: CoinselectAddressTypes;
38
- }[], outputs: {
39
- script?: Buffer;
40
- type?: CoinselectAddressTypes;
41
- }[], changeType: CoinselectAddressTypes): number;
42
- declare function uintOrNaN(v: number): number;
43
- declare function sumForgiving(range: {
44
- value: number;
45
- }[]): number;
46
- declare function sumOrNaN(range: {
47
- value: number;
48
- }[]): number;
49
- declare function finalize(inputs: CoinselectTxInput[], outputs: CoinselectTxOutput[], feeRate: number, changeType: CoinselectAddressTypes): {
50
- inputs?: CoinselectTxInput[];
51
- outputs?: CoinselectTxOutput[];
52
- fee: number;
53
- };
54
- export declare const utils: {
55
- dustThreshold: typeof dustThreshold;
56
- finalize: typeof finalize;
57
- inputBytes: typeof inputBytes;
58
- outputBytes: typeof outputBytes;
59
- sumOrNaN: typeof sumOrNaN;
60
- sumForgiving: typeof sumForgiving;
61
- transactionBytes: typeof transactionBytes;
62
- uintOrNaN: typeof uintOrNaN;
63
- };
64
- export {};