@btc-vision/wallet-sdk 1.0.2 → 1.0.5
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/es/bundle.js +1 -1
- package/es/bundle.js.LICENSE.txt +2 -2
- package/lib/address/index.js +50 -94
- package/lib/bitcoin-core.js +7 -47
- package/lib/constants.js +1 -4
- package/lib/error.js +6 -10
- package/lib/index.js +14 -53
- package/lib/keyring/hd-keyring.js +40 -89
- package/lib/keyring/index.js +4 -20
- package/lib/keyring/interfaces/SimpleKeyringOptions.js +16 -31
- package/lib/keyring/keystone-keyring.js +142 -211
- package/lib/keyring/simple-keyring.js +13 -18
- package/lib/message/bip322-simple.js +31 -81
- package/lib/message/deterministic-ecdsa.js +7 -43
- package/lib/message/ecdsa.js +10 -17
- package/lib/message/index.js +3 -19
- package/lib/network/index.js +12 -17
- package/lib/runes/index.js +1 -17
- package/lib/runes/rund_id.js +5 -10
- package/lib/runes/varint.js +6 -12
- package/lib/transaction/index.js +3 -19
- package/lib/transaction/inscription-utxo.js +9 -10
- package/lib/transaction/transaction.js +137 -142
- package/lib/transaction/utxo.js +13 -18
- package/lib/tx-helpers/index.js +8 -18
- package/lib/tx-helpers/send-atomicals-ft.js +45 -59
- package/lib/tx-helpers/send-atomicals-nft.js +29 -43
- package/lib/tx-helpers/send-btc.js +53 -70
- package/lib/tx-helpers/send-inscription.js +32 -46
- package/lib/tx-helpers/send-inscriptions.js +28 -42
- package/lib/tx-helpers/send-runes.js +83 -100
- package/lib/tx-helpers/split-inscription-utxo.js +39 -53
- package/lib/types.js +2 -5
- package/lib/utils.js +16 -29
- package/lib/wallet/abstract-wallet.js +1 -2
- package/lib/wallet/estimate-wallet.js +130 -147
- package/lib/wallet/index.js +3 -19
- package/lib/wallet/local-wallet.js +134 -150
- package/package.json +21 -12
- package/lib/address/index.d.ts +0 -36
- package/lib/bitcoin-core.d.ts +0 -5
- package/lib/constants.d.ts +0 -1
- package/lib/error.d.ts +0 -20
- package/lib/index.d.ts +0 -14
- package/lib/keyring/hd-keyring.d.ts +0 -50
- package/lib/keyring/index.d.ts +0 -4
- package/lib/keyring/interfaces/SimpleKeyringOptions.d.ts +0 -52
- package/lib/keyring/keystone-keyring.d.ts +0 -82
- package/lib/keyring/simple-keyring.d.ts +0 -11
- package/lib/message/bip322-simple.d.ts +0 -19
- package/lib/message/deterministic-ecdsa.d.ts +0 -2
- package/lib/message/ecdsa.d.ts +0 -3
- package/lib/message/index.d.ts +0 -3
- package/lib/network/index.d.ts +0 -14
- package/lib/runes/index.d.ts +0 -1
- package/lib/runes/rund_id.d.ts +0 -11
- package/lib/runes/varint.d.ts +0 -14
- package/lib/src/address/index.d.ts +0 -36
- package/lib/src/bitcoin-core.d.ts +0 -5
- package/lib/src/constants.d.ts +0 -1
- package/lib/src/error.d.ts +0 -20
- package/lib/src/index.d.ts +0 -14
- package/lib/src/keyring/hd-keyring.d.ts +0 -50
- package/lib/src/keyring/index.d.ts +0 -4
- package/lib/src/keyring/interfaces/SimpleKeyringOptions.d.ts +0 -52
- package/lib/src/keyring/keystone-keyring.d.ts +0 -82
- package/lib/src/keyring/simple-keyring.d.ts +0 -11
- package/lib/src/message/bip322-simple.d.ts +0 -19
- package/lib/src/message/deterministic-ecdsa.d.ts +0 -2
- package/lib/src/message/ecdsa.d.ts +0 -3
- package/lib/src/message/index.d.ts +0 -3
- package/lib/src/network/index.d.ts +0 -14
- package/lib/src/runes/index.d.ts +0 -1
- package/lib/src/runes/rund_id.d.ts +0 -11
- package/lib/src/runes/varint.d.ts +0 -14
- package/lib/src/transaction/index.d.ts +0 -3
- package/lib/src/transaction/inscription-utxo.d.ts +0 -33
- package/lib/src/transaction/transaction.d.ts +0 -51
- package/lib/src/transaction/utxo.d.ts +0 -35
- package/lib/src/tx-helpers/index.d.ts +0 -8
- package/lib/src/tx-helpers/send-atomicals-ft.d.ts +0 -16
- package/lib/src/tx-helpers/send-atomicals-nft.d.ts +0 -14
- package/lib/src/tx-helpers/send-btc.d.ts +0 -28
- package/lib/src/tx-helpers/send-inscription.d.ts +0 -16
- package/lib/src/tx-helpers/send-inscriptions.d.ts +0 -14
- package/lib/src/tx-helpers/send-runes.d.ts +0 -19
- package/lib/src/tx-helpers/split-inscription-utxo.d.ts +0 -15
- package/lib/src/types.d.ts +0 -59
- package/lib/src/utils.d.ts +0 -23
- package/lib/src/wallet/abstract-wallet.d.ts +0 -6
- package/lib/src/wallet/estimate-wallet.d.ts +0 -23
- package/lib/src/wallet/index.d.ts +0 -3
- package/lib/src/wallet/local-wallet.d.ts +0 -23
- package/lib/test/address/address.test.d.ts +0 -1
- package/lib/test/keyring/hd-keyring.test.d.ts +0 -1
- package/lib/test/keyring/keystone-keyring.test.d.ts +0 -1
- package/lib/test/keyring/simple-keyring.test.d.ts +0 -1
- package/lib/test/message/message.test.d.ts +0 -1
- package/lib/test/runes/varint.test.d.ts +0 -1
- package/lib/test/transaction/transaction.test.d.ts +0 -1
- package/lib/test/transaction/utxo.test.d.ts +0 -1
- package/lib/test/tx-helpers/send-atomicals-ft.test.d.ts +0 -1
- package/lib/test/tx-helpers/send-atomicals-nft.test.d.ts +0 -1
- package/lib/test/tx-helpers/send-btc.test.d.ts +0 -1
- package/lib/test/tx-helpers/send-inscription.test.d.ts +0 -1
- package/lib/test/tx-helpers/send-inscriptions.test.d.ts +0 -1
- package/lib/test/tx-helpers/send-runes.test.d.ts +0 -1
- package/lib/test/tx-helpers/split-inscription-utxo.test.d.ts +0 -1
- package/lib/test/tx-helpers/utils.d.ts +0 -217
- package/lib/test/utils.d.ts +0 -4
- package/lib/test/wallet/local-wallet.test.d.ts +0 -1
- package/lib/transaction/index.d.ts +0 -3
- package/lib/transaction/inscription-utxo.d.ts +0 -33
- package/lib/transaction/transaction.d.ts +0 -51
- package/lib/transaction/utxo.d.ts +0 -35
- package/lib/tx-helpers/index.d.ts +0 -8
- package/lib/tx-helpers/send-atomicals-ft.d.ts +0 -16
- package/lib/tx-helpers/send-atomicals-nft.d.ts +0 -14
- package/lib/tx-helpers/send-btc.d.ts +0 -28
- package/lib/tx-helpers/send-inscription.d.ts +0 -16
- package/lib/tx-helpers/send-inscriptions.d.ts +0 -14
- package/lib/tx-helpers/send-runes.d.ts +0 -19
- package/lib/tx-helpers/split-inscription-utxo.d.ts +0 -15
- package/lib/types.d.ts +0 -59
- package/lib/utils.d.ts +0 -23
- package/lib/wallet/abstract-wallet.d.ts +0 -6
- package/lib/wallet/estimate-wallet.d.ts +0 -23
- package/lib/wallet/index.d.ts +0 -3
- package/lib/wallet/local-wallet.d.ts +0 -23
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Transaction = void 0;
|
|
13
|
-
const address_1 = require("../address");
|
|
14
|
-
const bitcoin_core_1 = require("../bitcoin-core");
|
|
15
|
-
const constants_1 = require("../constants");
|
|
16
|
-
const error_1 = require("../error");
|
|
17
|
-
const network_1 = require("../network");
|
|
18
|
-
const types_1 = require("../types");
|
|
19
|
-
const utils_1 = require("../utils");
|
|
20
|
-
const wallet_1 = require("../wallet");
|
|
21
|
-
const utxo_1 = require("./utxo");
|
|
1
|
+
import { payments } from 'bitcoinjs-lib';
|
|
2
|
+
import { addressToScriptPk } from '../address';
|
|
3
|
+
import { bitcoin } from '../bitcoin-core';
|
|
4
|
+
import { UTXO_DUST } from '../constants';
|
|
5
|
+
import { ErrorCodes, WalletUtilsError } from '../error';
|
|
6
|
+
import { NetworkType, toPsbtNetwork } from '../network';
|
|
7
|
+
import { AddressType } from '../types';
|
|
8
|
+
import { toXOnly } from '../utils';
|
|
9
|
+
import { EstimateWallet } from '../wallet';
|
|
10
|
+
import { utxoHelper } from './utxo';
|
|
22
11
|
/**
|
|
23
12
|
* Convert UnspentOutput to PSBT TxInput
|
|
24
13
|
*/
|
|
25
14
|
function utxoToInput(utxo, estimate) {
|
|
26
|
-
if (utxo.addressType ===
|
|
15
|
+
if (utxo.addressType === AddressType.P2TR || utxo.addressType === AddressType.M44_P2TR) {
|
|
27
16
|
const data = {
|
|
28
17
|
hash: utxo.txid,
|
|
29
18
|
index: utxo.vout,
|
|
@@ -31,14 +20,14 @@ function utxoToInput(utxo, estimate) {
|
|
|
31
20
|
value: utxo.satoshis,
|
|
32
21
|
script: Buffer.from(utxo.scriptPk, 'hex')
|
|
33
22
|
},
|
|
34
|
-
tapInternalKey:
|
|
23
|
+
tapInternalKey: toXOnly(Buffer.from(utxo.pubkey, 'hex'))
|
|
35
24
|
};
|
|
36
25
|
return {
|
|
37
26
|
data,
|
|
38
27
|
utxo
|
|
39
28
|
};
|
|
40
29
|
}
|
|
41
|
-
else if (utxo.addressType ===
|
|
30
|
+
else if (utxo.addressType === AddressType.P2WPKH || utxo.addressType === AddressType.M44_P2WPKH) {
|
|
42
31
|
const data = {
|
|
43
32
|
hash: utxo.txid,
|
|
44
33
|
index: utxo.vout,
|
|
@@ -52,7 +41,7 @@ function utxoToInput(utxo, estimate) {
|
|
|
52
41
|
utxo
|
|
53
42
|
};
|
|
54
43
|
}
|
|
55
|
-
else if (utxo.addressType ===
|
|
44
|
+
else if (utxo.addressType === AddressType.P2PKH) {
|
|
56
45
|
if (!utxo.rawtx || estimate) {
|
|
57
46
|
const data = {
|
|
58
47
|
hash: utxo.txid,
|
|
@@ -79,8 +68,8 @@ function utxoToInput(utxo, estimate) {
|
|
|
79
68
|
};
|
|
80
69
|
}
|
|
81
70
|
}
|
|
82
|
-
else if (utxo.addressType ===
|
|
83
|
-
const redeemData =
|
|
71
|
+
else if (utxo.addressType === AddressType.P2SH_P2WPKH) {
|
|
72
|
+
const redeemData = bitcoin.payments.p2wpkh({
|
|
84
73
|
pubkey: Buffer.from(utxo.pubkey, 'hex')
|
|
85
74
|
});
|
|
86
75
|
const data = {
|
|
@@ -97,21 +86,36 @@ function utxoToInput(utxo, estimate) {
|
|
|
97
86
|
utxo
|
|
98
87
|
};
|
|
99
88
|
}
|
|
89
|
+
else {
|
|
90
|
+
return {
|
|
91
|
+
data: {
|
|
92
|
+
hash: utxo.txid,
|
|
93
|
+
index: utxo.vout,
|
|
94
|
+
witnessUtxo: {
|
|
95
|
+
value: utxo.satoshis,
|
|
96
|
+
script: Buffer.from(utxo.scriptPk, 'hex')
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
utxo
|
|
100
|
+
};
|
|
101
|
+
}
|
|
100
102
|
}
|
|
101
103
|
/**
|
|
102
104
|
* Transaction
|
|
103
105
|
*/
|
|
104
|
-
class Transaction {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
export class Transaction {
|
|
107
|
+
outputs = [];
|
|
108
|
+
changedAddress = '';
|
|
109
|
+
utxos = [];
|
|
110
|
+
inputs = [];
|
|
111
|
+
changeOutputIndex = -1;
|
|
112
|
+
networkType = NetworkType.MAINNET;
|
|
113
|
+
feeRate = 1;
|
|
114
|
+
enableRBF = true;
|
|
115
|
+
_cacheNetworkFee = 0;
|
|
116
|
+
_cacheBtcUtxos = [];
|
|
117
|
+
_cacheToSignInputs = [];
|
|
118
|
+
constructor() { }
|
|
115
119
|
setNetworkType(network) {
|
|
116
120
|
this.networkType = network;
|
|
117
121
|
}
|
|
@@ -141,13 +145,11 @@ class Transaction {
|
|
|
141
145
|
getUnspent() {
|
|
142
146
|
return this.getTotalInput() - this.getTotalOutput();
|
|
143
147
|
}
|
|
144
|
-
calNetworkFee() {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return fee;
|
|
150
|
-
});
|
|
148
|
+
async calNetworkFee() {
|
|
149
|
+
const psbt = await this.createEstimatePsbt();
|
|
150
|
+
const txSize = psbt.extractTransaction(true).virtualSize();
|
|
151
|
+
const fee = Math.ceil(txSize * this.feeRate);
|
|
152
|
+
return fee;
|
|
151
153
|
}
|
|
152
154
|
addOutput(address, value) {
|
|
153
155
|
this.outputs.push({
|
|
@@ -156,7 +158,7 @@ class Transaction {
|
|
|
156
158
|
});
|
|
157
159
|
}
|
|
158
160
|
addOpreturn(data) {
|
|
159
|
-
const embed =
|
|
161
|
+
const embed = payments.embed({ data });
|
|
160
162
|
this.outputs.push({
|
|
161
163
|
script: embed.output,
|
|
162
164
|
value: 0
|
|
@@ -193,10 +195,10 @@ class Transaction {
|
|
|
193
195
|
this.outputs.splice(-count);
|
|
194
196
|
}
|
|
195
197
|
toPsbt() {
|
|
196
|
-
const network =
|
|
197
|
-
const psbt = new
|
|
198
|
+
const network = toPsbtNetwork(this.networkType);
|
|
199
|
+
const psbt = new bitcoin.Psbt({ network });
|
|
198
200
|
this.inputs.forEach((v, index) => {
|
|
199
|
-
if (v.utxo.addressType ===
|
|
201
|
+
if (v.utxo.addressType === AddressType.P2PKH) {
|
|
200
202
|
if (v.data.witnessUtxo) {
|
|
201
203
|
//@ts-ignore
|
|
202
204
|
psbt.__CACHE.__UNSAFE_SIGN_NONSEGWIT = true;
|
|
@@ -234,113 +236,107 @@ class Transaction {
|
|
|
234
236
|
tx.outputs = this.outputs.map((v) => v);
|
|
235
237
|
return tx;
|
|
236
238
|
}
|
|
237
|
-
createEstimatePsbt() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
v.scriptPk = scriptPk;
|
|
245
|
-
});
|
|
246
|
-
tx.inputs = [];
|
|
247
|
-
tx.utxos.forEach((v) => {
|
|
248
|
-
const input = utxoToInput(v, true);
|
|
249
|
-
tx.inputs.push(input);
|
|
250
|
-
});
|
|
251
|
-
const psbt = tx.toPsbt();
|
|
252
|
-
const toSignInputs = tx.inputs.map((v, index) => ({
|
|
253
|
-
index,
|
|
254
|
-
publicKey: estimateWallet.pubkey
|
|
255
|
-
}));
|
|
256
|
-
yield estimateWallet.signPsbt(psbt, {
|
|
257
|
-
autoFinalized: true,
|
|
258
|
-
toSignInputs: toSignInputs
|
|
259
|
-
});
|
|
260
|
-
return psbt;
|
|
239
|
+
async createEstimatePsbt() {
|
|
240
|
+
const estimateWallet = EstimateWallet.fromRandom(this.inputs[0].utxo.addressType, this.networkType);
|
|
241
|
+
const scriptPk = addressToScriptPk(estimateWallet.address, this.networkType).toString('hex');
|
|
242
|
+
const tx = this.clone();
|
|
243
|
+
tx.utxos.forEach((v) => {
|
|
244
|
+
v.pubkey = estimateWallet.pubkey;
|
|
245
|
+
v.scriptPk = scriptPk;
|
|
261
246
|
});
|
|
247
|
+
tx.inputs = [];
|
|
248
|
+
tx.utxos.forEach((v) => {
|
|
249
|
+
const input = utxoToInput(v, true);
|
|
250
|
+
tx.inputs.push(input);
|
|
251
|
+
});
|
|
252
|
+
const psbt = tx.toPsbt();
|
|
253
|
+
const toSignInputs = tx.inputs.map((v, index) => ({
|
|
254
|
+
index,
|
|
255
|
+
publicKey: estimateWallet.pubkey
|
|
256
|
+
}));
|
|
257
|
+
await estimateWallet.signPsbt(psbt, {
|
|
258
|
+
autoFinalized: true,
|
|
259
|
+
toSignInputs: toSignInputs
|
|
260
|
+
});
|
|
261
|
+
return psbt;
|
|
262
262
|
}
|
|
263
|
-
addSufficientUtxosForFee(btcUtxos, forceAsFee) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
throw new error_1.WalletUtilsError(error_1.ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
280
|
-
}
|
|
281
|
-
if (this.getTotalInput() < this.getTotalOutput()) {
|
|
282
|
-
throw new error_1.WalletUtilsError(error_1.ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
283
|
-
}
|
|
284
|
-
this._cacheNetworkFee = yield this.calNetworkFee();
|
|
285
|
-
}
|
|
286
|
-
const changeAmount = this.getTotalInput() - this.getTotalOutput() - Math.ceil(this._cacheNetworkFee);
|
|
287
|
-
if (changeAmount > constants_1.UTXO_DUST) {
|
|
288
|
-
this.removeChangeOutput();
|
|
289
|
-
this.addChangeOutput(changeAmount);
|
|
263
|
+
async addSufficientUtxosForFee(btcUtxos, forceAsFee) {
|
|
264
|
+
if (btcUtxos.length > 0) {
|
|
265
|
+
this._cacheBtcUtxos = btcUtxos;
|
|
266
|
+
const dummyBtcUtxo = Object.assign({}, btcUtxos[0]);
|
|
267
|
+
dummyBtcUtxo.satoshis = 2100000000000000;
|
|
268
|
+
this.addInput(dummyBtcUtxo);
|
|
269
|
+
this.addChangeOutput(0);
|
|
270
|
+
const networkFee = await this.calNetworkFee();
|
|
271
|
+
const dummyBtcUtxoSize = utxoHelper.getAddedVirtualSize(dummyBtcUtxo.addressType);
|
|
272
|
+
this._cacheNetworkFee = networkFee - dummyBtcUtxoSize * this.feeRate;
|
|
273
|
+
this.removeLastInput();
|
|
274
|
+
this.selectBtcUtxos();
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
if (forceAsFee) {
|
|
278
|
+
throw new WalletUtilsError(ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
290
279
|
}
|
|
291
|
-
|
|
292
|
-
|
|
280
|
+
if (this.getTotalInput() < this.getTotalOutput()) {
|
|
281
|
+
throw new WalletUtilsError(ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
293
282
|
}
|
|
294
|
-
|
|
295
|
-
}
|
|
283
|
+
this._cacheNetworkFee = await this.calNetworkFee();
|
|
284
|
+
}
|
|
285
|
+
const changeAmount = this.getTotalInput() - this.getTotalOutput() - Math.ceil(this._cacheNetworkFee);
|
|
286
|
+
if (changeAmount > UTXO_DUST) {
|
|
287
|
+
this.removeChangeOutput();
|
|
288
|
+
this.addChangeOutput(changeAmount);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
this.removeChangeOutput();
|
|
292
|
+
}
|
|
293
|
+
return this._cacheToSignInputs;
|
|
296
294
|
}
|
|
297
|
-
dumpTx(psbt) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
Fee
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
Inputs
|
|
295
|
+
async dumpTx(psbt) {
|
|
296
|
+
const tx = psbt.extractTransaction();
|
|
297
|
+
const feeRate = psbt.getFeeRate();
|
|
298
|
+
console.log(`
|
|
299
|
+
=============================================================================================
|
|
300
|
+
Summary
|
|
301
|
+
txid: ${tx.getId()}
|
|
302
|
+
Size: ${tx.byteLength()}
|
|
303
|
+
Fee Paid: ${psbt.getFee()}
|
|
304
|
+
Fee Rate: ${feeRate} sat/vB
|
|
305
|
+
Detail: ${psbt.txInputs.length} Inputs, ${psbt.txOutputs.length} Outputs
|
|
306
|
+
----------------------------------------------------------------------------------------------
|
|
307
|
+
Inputs
|
|
311
308
|
${this.inputs
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
=>${index} ${input.data.witnessUtxo.value} Sats
|
|
315
|
-
lock-size: ${input.data.witnessUtxo.script.length}
|
|
316
|
-
via ${input.data.hash} [${input.data.index}]
|
|
309
|
+
.map((input, index) => {
|
|
310
|
+
const str = `
|
|
311
|
+
=>${index} ${input.data.witnessUtxo.value} Sats
|
|
312
|
+
lock-size: ${input.data.witnessUtxo.script.length}
|
|
313
|
+
via ${input.data.hash} [${input.data.index}]
|
|
317
314
|
`;
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
total: ${this.getTotalInput()} Sats
|
|
322
|
-
----------------------------------------------------------------------------------------------
|
|
323
|
-
Outputs
|
|
315
|
+
return str;
|
|
316
|
+
})
|
|
317
|
+
.join('')}
|
|
318
|
+
total: ${this.getTotalInput()} Sats
|
|
319
|
+
----------------------------------------------------------------------------------------------
|
|
320
|
+
Outputs
|
|
324
321
|
${this.outputs
|
|
325
|
-
|
|
326
|
-
|
|
322
|
+
.map((output, index) => {
|
|
323
|
+
const str = `
|
|
327
324
|
=>${index} ${output.address} ${output.value} Sats`;
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
total: ${this.getTotalOutput()} Sats
|
|
333
|
-
=============================================================================================
|
|
325
|
+
return str;
|
|
326
|
+
})
|
|
327
|
+
.join('')}
|
|
328
|
+
|
|
329
|
+
total: ${this.getTotalOutput()} Sats
|
|
330
|
+
=============================================================================================
|
|
334
331
|
`);
|
|
335
|
-
});
|
|
336
332
|
}
|
|
337
333
|
selectBtcUtxos() {
|
|
338
334
|
const totalInput = this.getTotalInput();
|
|
339
335
|
const totalOutput = this.getTotalOutput() + this._cacheNetworkFee;
|
|
340
336
|
if (totalInput < totalOutput) {
|
|
341
|
-
const { selectedUtxos, remainingUtxos } =
|
|
337
|
+
const { selectedUtxos, remainingUtxos } = utxoHelper.selectBtcUtxos(this._cacheBtcUtxos, totalOutput - totalInput);
|
|
342
338
|
if (selectedUtxos.length == 0) {
|
|
343
|
-
throw new
|
|
339
|
+
throw new WalletUtilsError(ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
344
340
|
}
|
|
345
341
|
selectedUtxos.forEach((v) => {
|
|
346
342
|
this.addInput(v);
|
|
@@ -348,11 +344,10 @@ total: ${this.getTotalOutput()} Sats
|
|
|
348
344
|
index: this.inputs.length - 1,
|
|
349
345
|
publicKey: v.pubkey
|
|
350
346
|
});
|
|
351
|
-
this._cacheNetworkFee +=
|
|
347
|
+
this._cacheNetworkFee += utxoHelper.getAddedVirtualSize(v.addressType) * this.feeRate;
|
|
352
348
|
});
|
|
353
349
|
this._cacheBtcUtxos = remainingUtxos;
|
|
354
350
|
this.selectBtcUtxos();
|
|
355
351
|
}
|
|
356
352
|
}
|
|
357
353
|
}
|
|
358
|
-
exports.Transaction = Transaction;
|
package/lib/transaction/utxo.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exports.getUtxoDust = getUtxoDust;
|
|
5
|
-
exports.getAddressUtxoDust = getAddressUtxoDust;
|
|
6
|
-
const address_1 = require("../address");
|
|
7
|
-
const network_1 = require("../network");
|
|
8
|
-
const types_1 = require("../types");
|
|
1
|
+
import { decodeAddress } from '../address';
|
|
2
|
+
import { NetworkType } from '../network';
|
|
3
|
+
import { AddressType } from '../types';
|
|
9
4
|
function hasInscription(utxos) {
|
|
10
5
|
if (utxos.find((v) => v.inscriptions.length > 0)) {
|
|
11
6
|
return true;
|
|
@@ -64,25 +59,25 @@ function selectBtcUtxos(utxos, targetAmount) {
|
|
|
64
59
|
* return the added virtual size of the utxo
|
|
65
60
|
*/
|
|
66
61
|
function getAddedVirtualSize(addressType) {
|
|
67
|
-
if (addressType ===
|
|
62
|
+
if (addressType === AddressType.P2WPKH || addressType === AddressType.M44_P2WPKH) {
|
|
68
63
|
return 41 + (1 + 1 + 72 + 1 + 33) / 4;
|
|
69
64
|
}
|
|
70
|
-
else if (addressType ===
|
|
65
|
+
else if (addressType === AddressType.P2TR || addressType === AddressType.M44_P2TR) {
|
|
71
66
|
return 41 + (1 + 1 + 64) / 4;
|
|
72
67
|
}
|
|
73
|
-
else if (addressType ===
|
|
68
|
+
else if (addressType === AddressType.P2PKH) {
|
|
74
69
|
return 41 + 1 + 1 + 72 + 1 + 33;
|
|
75
70
|
}
|
|
76
|
-
else if (addressType ===
|
|
71
|
+
else if (addressType === AddressType.P2SH_P2WPKH) {
|
|
77
72
|
return 41 + 24 + (1 + 1 + 72 + 1 + 33) / 4;
|
|
78
73
|
}
|
|
79
74
|
throw new Error('unknown address type');
|
|
80
75
|
}
|
|
81
|
-
function getUtxoDust(addressType) {
|
|
82
|
-
if (addressType ===
|
|
76
|
+
export function getUtxoDust(addressType) {
|
|
77
|
+
if (addressType === AddressType.P2WPKH || addressType === AddressType.M44_P2WPKH) {
|
|
83
78
|
return 294;
|
|
84
79
|
}
|
|
85
|
-
else if (addressType ===
|
|
80
|
+
else if (addressType === AddressType.P2TR || addressType === AddressType.M44_P2TR) {
|
|
86
81
|
return 330;
|
|
87
82
|
}
|
|
88
83
|
else {
|
|
@@ -91,10 +86,10 @@ function getUtxoDust(addressType) {
|
|
|
91
86
|
}
|
|
92
87
|
// deprecated
|
|
93
88
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
94
|
-
function getAddressUtxoDust(address, networkType =
|
|
95
|
-
return
|
|
89
|
+
export function getAddressUtxoDust(address, networkType = NetworkType.MAINNET) {
|
|
90
|
+
return decodeAddress(address).dust;
|
|
96
91
|
}
|
|
97
|
-
|
|
92
|
+
export const utxoHelper = {
|
|
98
93
|
hasAtomicalsFT,
|
|
99
94
|
hasAtomicalsNFT,
|
|
100
95
|
hasAtomicals,
|
package/lib/tx-helpers/index.js
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Object.defineProperty(exports, "sendAllBTC", { enumerable: true, get: function () { return send_btc_1.sendAllBTC; } });
|
|
10
|
-
Object.defineProperty(exports, "sendBTC", { enumerable: true, get: function () { return send_btc_1.sendBTC; } });
|
|
11
|
-
const send_inscription_1 = require("./send-inscription");
|
|
12
|
-
Object.defineProperty(exports, "sendInscription", { enumerable: true, get: function () { return send_inscription_1.sendInscription; } });
|
|
13
|
-
const send_inscriptions_1 = require("./send-inscriptions");
|
|
14
|
-
Object.defineProperty(exports, "sendInscriptions", { enumerable: true, get: function () { return send_inscriptions_1.sendInscriptions; } });
|
|
15
|
-
const send_runes_1 = require("./send-runes");
|
|
16
|
-
Object.defineProperty(exports, "sendRunes", { enumerable: true, get: function () { return send_runes_1.sendRunes; } });
|
|
17
|
-
const split_inscription_utxo_1 = require("./split-inscription-utxo");
|
|
18
|
-
Object.defineProperty(exports, "splitInscriptionUtxo", { enumerable: true, get: function () { return split_inscription_utxo_1.splitInscriptionUtxo; } });
|
|
1
|
+
import { sendAtomicalsFT } from './send-atomicals-ft';
|
|
2
|
+
import { sendAtomicalsNFT } from './send-atomicals-nft';
|
|
3
|
+
import { sendAllBTC, sendBTC } from './send-btc';
|
|
4
|
+
import { sendInscription } from './send-inscription';
|
|
5
|
+
import { sendInscriptions } from './send-inscriptions';
|
|
6
|
+
import { sendRunes } from './send-runes';
|
|
7
|
+
import { splitInscriptionUtxo } from './split-inscription-utxo';
|
|
8
|
+
export { sendAllBTC, sendAtomicalsFT, sendAtomicalsNFT, sendBTC, sendInscription, sendInscriptions, sendRunes, splitInscriptionUtxo };
|
|
@@ -1,65 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.sendAtomicalsFT = sendAtomicalsFT;
|
|
13
|
-
const error_1 = require("../error");
|
|
14
|
-
const transaction_1 = require("../transaction");
|
|
1
|
+
import { ErrorCodes, WalletUtilsError } from '../error';
|
|
2
|
+
import { Transaction, utxoHelper } from '../transaction';
|
|
15
3
|
// only one arc20 can be send
|
|
16
|
-
function sendAtomicalsFT(params) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
4
|
+
export async function sendAtomicalsFT(params) {
|
|
5
|
+
const { assetUtxos, btcUtxos, toAddress, networkType, changeAssetAddress, sendAmount, changeAddress, feeRate, enableRBF = true } = params;
|
|
6
|
+
// safe check
|
|
7
|
+
if (utxoHelper.hasAtomicalsNFT(assetUtxos) || utxoHelper.hasInscription(assetUtxos)) {
|
|
8
|
+
throw new WalletUtilsError(ErrorCodes.NOT_SAFE_UTXOS);
|
|
9
|
+
}
|
|
10
|
+
if (utxoHelper.hasAnyAssets(btcUtxos)) {
|
|
11
|
+
throw new WalletUtilsError(ErrorCodes.NOT_SAFE_UTXOS);
|
|
12
|
+
}
|
|
13
|
+
const tx = new Transaction();
|
|
14
|
+
tx.setNetworkType(networkType);
|
|
15
|
+
tx.setFeeRate(feeRate);
|
|
16
|
+
tx.setEnableRBF(enableRBF);
|
|
17
|
+
tx.setChangeAddress(changeAddress);
|
|
18
|
+
const toSignInputs = [];
|
|
19
|
+
let totalInputFTAmount = 0;
|
|
20
|
+
assetUtxos.forEach((v) => {
|
|
21
|
+
if (v.atomicals.length > 1) {
|
|
22
|
+
throw new WalletUtilsError(ErrorCodes.ONLY_ONE_ARC20_CAN_BE_SENT);
|
|
25
23
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
tx.setEnableRBF(enableRBF);
|
|
30
|
-
tx.setChangeAddress(changeAddress);
|
|
31
|
-
const toSignInputs = [];
|
|
32
|
-
let totalInputFTAmount = 0;
|
|
33
|
-
assetUtxos.forEach((v) => {
|
|
34
|
-
if (v.atomicals.length > 1) {
|
|
35
|
-
throw new error_1.WalletUtilsError(error_1.ErrorCodes.ONLY_ONE_ARC20_CAN_BE_SENT);
|
|
24
|
+
v.atomicals.forEach((w) => {
|
|
25
|
+
if (!w.atomicalValue) {
|
|
26
|
+
w.atomicalValue = v.satoshis;
|
|
36
27
|
}
|
|
37
|
-
|
|
38
|
-
if (!w.atomicalValue) {
|
|
39
|
-
w.atomicalValue = v.satoshis;
|
|
40
|
-
}
|
|
41
|
-
totalInputFTAmount += w.atomicalValue;
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
if (sendAmount > totalInputFTAmount) {
|
|
45
|
-
throw new error_1.WalletUtilsError(error_1.ErrorCodes.INSUFFICIENT_ASSET_UTXO);
|
|
46
|
-
}
|
|
47
|
-
// add assets
|
|
48
|
-
assetUtxos.forEach((v, index) => {
|
|
49
|
-
tx.addInput(v);
|
|
50
|
-
toSignInputs.push({ index, publicKey: v.pubkey });
|
|
28
|
+
totalInputFTAmount += w.atomicalValue;
|
|
51
29
|
});
|
|
52
|
-
// add receiver
|
|
53
|
-
tx.addOutput(toAddress, sendAmount);
|
|
54
|
-
// add change
|
|
55
|
-
const changeArc20Amount = totalInputFTAmount - sendAmount;
|
|
56
|
-
if (changeArc20Amount > 0) {
|
|
57
|
-
tx.addOutput(changeAssetAddress, changeArc20Amount);
|
|
58
|
-
}
|
|
59
|
-
// add btc
|
|
60
|
-
const _toSignInputs = yield tx.addSufficientUtxosForFee(btcUtxos, true);
|
|
61
|
-
toSignInputs.push(..._toSignInputs);
|
|
62
|
-
const psbt = tx.toPsbt();
|
|
63
|
-
return { psbt, toSignInputs };
|
|
64
30
|
});
|
|
31
|
+
if (sendAmount > totalInputFTAmount) {
|
|
32
|
+
throw new WalletUtilsError(ErrorCodes.INSUFFICIENT_ASSET_UTXO);
|
|
33
|
+
}
|
|
34
|
+
// add assets
|
|
35
|
+
assetUtxos.forEach((v, index) => {
|
|
36
|
+
tx.addInput(v);
|
|
37
|
+
toSignInputs.push({ index, publicKey: v.pubkey });
|
|
38
|
+
});
|
|
39
|
+
// add receiver
|
|
40
|
+
tx.addOutput(toAddress, sendAmount);
|
|
41
|
+
// add change
|
|
42
|
+
const changeArc20Amount = totalInputFTAmount - sendAmount;
|
|
43
|
+
if (changeArc20Amount > 0) {
|
|
44
|
+
tx.addOutput(changeAssetAddress, changeArc20Amount);
|
|
45
|
+
}
|
|
46
|
+
// add btc
|
|
47
|
+
const _toSignInputs = await tx.addSufficientUtxosForFee(btcUtxos, true);
|
|
48
|
+
toSignInputs.push(..._toSignInputs);
|
|
49
|
+
const psbt = tx.toPsbt();
|
|
50
|
+
return { psbt, toSignInputs };
|
|
65
51
|
}
|