@btc-vision/wallet-sdk 1.0.0 → 1.0.4
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 +4 -4
- package/lib/address/index.js +50 -85
- package/lib/bitcoin-core.js +7 -37
- package/lib/constants.js +1 -4
- package/lib/error.js +6 -10
- package/lib/index.js +14 -43
- package/lib/keyring/hd-keyring.js +40 -79
- package/lib/keyring/index.js +4 -20
- package/lib/keyring/interfaces/SimpleKeyringOptions.js +16 -31
- package/lib/keyring/keystone-keyring.js +142 -201
- package/lib/keyring/simple-keyring.js +13 -18
- package/lib/message/bip322-simple.js +31 -71
- package/lib/message/deterministic-ecdsa.js +19 -40
- package/lib/message/ecdsa.js +10 -18
- 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 +8 -13
- package/lib/runes/varint.js +6 -12
- package/lib/transaction/index.js +3 -19
- package/lib/transaction/inscription-utxo.js +45 -38
- package/lib/transaction/transaction.js +134 -139
- package/lib/transaction/utxo.js +13 -18
- package/lib/tx-helpers/index.js +8 -18
- package/lib/tx-helpers/send-atomicals-ft.js +45 -60
- package/lib/tx-helpers/send-atomicals-nft.js +29 -44
- package/lib/tx-helpers/send-btc.js +53 -71
- package/lib/tx-helpers/send-inscription.js +32 -47
- package/lib/tx-helpers/send-inscriptions.js +28 -43
- package/lib/tx-helpers/send-runes.js +83 -97
- package/lib/tx-helpers/split-inscription-utxo.js +39 -54
- 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 +103 -95
- package/lib/address/index.d.ts +0 -37
- 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 -53
- 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 -15
- package/lib/src/address/index.d.ts +0 -37
- 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 -53
- 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 -15
- 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 -52
- 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 -52
- 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,91 +236,66 @@ 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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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;
|
|
246
|
+
});
|
|
247
|
+
tx.inputs = [];
|
|
248
|
+
tx.utxos.forEach((v) => {
|
|
249
|
+
const input = utxoToInput(v, true);
|
|
250
|
+
tx.inputs.push(input);
|
|
261
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
index: this.inputs.length - 1,
|
|
275
|
-
publicKey: v.pubkey
|
|
276
|
-
});
|
|
277
|
-
this._cacheNetworkFee += utxo_1.utxoHelper.getAddedVirtualSize(v.addressType) * this.feeRate;
|
|
278
|
-
});
|
|
279
|
-
this._cacheBtcUtxos = remainingUtxos;
|
|
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();
|
|
280
274
|
this.selectBtcUtxos();
|
|
281
275
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (btcUtxos.length > 0) {
|
|
286
|
-
this._cacheBtcUtxos = btcUtxos;
|
|
287
|
-
const dummyBtcUtxo = Object.assign({}, btcUtxos[0]);
|
|
288
|
-
dummyBtcUtxo.satoshis = 2100000000000000;
|
|
289
|
-
this.addInput(dummyBtcUtxo);
|
|
290
|
-
this.addChangeOutput(0);
|
|
291
|
-
const networkFee = yield this.calNetworkFee();
|
|
292
|
-
const dummyBtcUtxoSize = utxo_1.utxoHelper.getAddedVirtualSize(dummyBtcUtxo.addressType);
|
|
293
|
-
this._cacheNetworkFee = networkFee - dummyBtcUtxoSize * this.feeRate;
|
|
294
|
-
this.removeLastInput();
|
|
295
|
-
this.selectBtcUtxos();
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
if (forceAsFee) {
|
|
299
|
-
throw new error_1.WalletUtilsError(error_1.ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
300
|
-
}
|
|
301
|
-
if (this.getTotalInput() < this.getTotalOutput()) {
|
|
302
|
-
throw new error_1.WalletUtilsError(error_1.ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
303
|
-
}
|
|
304
|
-
this._cacheNetworkFee = yield this.calNetworkFee();
|
|
305
|
-
}
|
|
306
|
-
const changeAmount = this.getTotalInput() - this.getTotalOutput() - Math.ceil(this._cacheNetworkFee);
|
|
307
|
-
if (changeAmount > constants_1.UTXO_DUST) {
|
|
308
|
-
this.removeChangeOutput();
|
|
309
|
-
this.addChangeOutput(changeAmount);
|
|
276
|
+
else {
|
|
277
|
+
if (forceAsFee) {
|
|
278
|
+
throw new WalletUtilsError(ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
310
279
|
}
|
|
311
|
-
|
|
312
|
-
|
|
280
|
+
if (this.getTotalInput() < this.getTotalOutput()) {
|
|
281
|
+
throw new WalletUtilsError(ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
313
282
|
}
|
|
314
|
-
|
|
315
|
-
}
|
|
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;
|
|
316
294
|
}
|
|
317
|
-
dumpTx(psbt) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
console.log(`
|
|
295
|
+
async dumpTx(psbt) {
|
|
296
|
+
const tx = psbt.extractTransaction();
|
|
297
|
+
const feeRate = psbt.getFeeRate();
|
|
298
|
+
console.log(`
|
|
322
299
|
=============================================================================================
|
|
323
300
|
Summary
|
|
324
301
|
txid: ${tx.getId()}
|
|
@@ -329,30 +306,48 @@ Summary
|
|
|
329
306
|
----------------------------------------------------------------------------------------------
|
|
330
307
|
Inputs
|
|
331
308
|
${this.inputs
|
|
332
|
-
|
|
333
|
-
|
|
309
|
+
.map((input, index) => {
|
|
310
|
+
const str = `
|
|
334
311
|
=>${index} ${input.data.witnessUtxo.value} Sats
|
|
335
312
|
lock-size: ${input.data.witnessUtxo.script.length}
|
|
336
313
|
via ${input.data.hash} [${input.data.index}]
|
|
337
314
|
`;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
315
|
+
return str;
|
|
316
|
+
})
|
|
317
|
+
.join('')}
|
|
341
318
|
total: ${this.getTotalInput()} Sats
|
|
342
319
|
----------------------------------------------------------------------------------------------
|
|
343
320
|
Outputs
|
|
344
321
|
${this.outputs
|
|
345
|
-
|
|
346
|
-
|
|
322
|
+
.map((output, index) => {
|
|
323
|
+
const str = `
|
|
347
324
|
=>${index} ${output.address} ${output.value} Sats`;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
325
|
+
return str;
|
|
326
|
+
})
|
|
327
|
+
.join('')}
|
|
351
328
|
|
|
352
329
|
total: ${this.getTotalOutput()} Sats
|
|
353
330
|
=============================================================================================
|
|
354
331
|
`);
|
|
355
|
-
|
|
332
|
+
}
|
|
333
|
+
selectBtcUtxos() {
|
|
334
|
+
const totalInput = this.getTotalInput();
|
|
335
|
+
const totalOutput = this.getTotalOutput() + this._cacheNetworkFee;
|
|
336
|
+
if (totalInput < totalOutput) {
|
|
337
|
+
const { selectedUtxos, remainingUtxos } = utxoHelper.selectBtcUtxos(this._cacheBtcUtxos, totalOutput - totalInput);
|
|
338
|
+
if (selectedUtxos.length == 0) {
|
|
339
|
+
throw new WalletUtilsError(ErrorCodes.INSUFFICIENT_BTC_UTXO);
|
|
340
|
+
}
|
|
341
|
+
selectedUtxos.forEach((v) => {
|
|
342
|
+
this.addInput(v);
|
|
343
|
+
this._cacheToSignInputs.push({
|
|
344
|
+
index: this.inputs.length - 1,
|
|
345
|
+
publicKey: v.pubkey
|
|
346
|
+
});
|
|
347
|
+
this._cacheNetworkFee += utxoHelper.getAddedVirtualSize(v.addressType) * this.feeRate;
|
|
348
|
+
});
|
|
349
|
+
this._cacheBtcUtxos = remainingUtxos;
|
|
350
|
+
this.selectBtcUtxos();
|
|
351
|
+
}
|
|
356
352
|
}
|
|
357
353
|
}
|
|
358
|
-
exports.Transaction = Transaction;
|
package/lib/transaction/utxo.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const address_1 = require("../address");
|
|
5
|
-
const network_1 = require("../network");
|
|
6
|
-
const types_1 = require("../types");
|
|
1
|
+
import { decodeAddress } from '../address';
|
|
2
|
+
import { NetworkType } from '../network';
|
|
3
|
+
import { AddressType } from '../types';
|
|
7
4
|
function hasInscription(utxos) {
|
|
8
5
|
if (utxos.find((v) => v.inscriptions.length > 0)) {
|
|
9
6
|
return true;
|
|
@@ -62,39 +59,37 @@ function selectBtcUtxos(utxos, targetAmount) {
|
|
|
62
59
|
* return the added virtual size of the utxo
|
|
63
60
|
*/
|
|
64
61
|
function getAddedVirtualSize(addressType) {
|
|
65
|
-
if (addressType ===
|
|
62
|
+
if (addressType === AddressType.P2WPKH || addressType === AddressType.M44_P2WPKH) {
|
|
66
63
|
return 41 + (1 + 1 + 72 + 1 + 33) / 4;
|
|
67
64
|
}
|
|
68
|
-
else if (addressType ===
|
|
65
|
+
else if (addressType === AddressType.P2TR || addressType === AddressType.M44_P2TR) {
|
|
69
66
|
return 41 + (1 + 1 + 64) / 4;
|
|
70
67
|
}
|
|
71
|
-
else if (addressType ===
|
|
68
|
+
else if (addressType === AddressType.P2PKH) {
|
|
72
69
|
return 41 + 1 + 1 + 72 + 1 + 33;
|
|
73
70
|
}
|
|
74
|
-
else if (addressType ===
|
|
71
|
+
else if (addressType === AddressType.P2SH_P2WPKH) {
|
|
75
72
|
return 41 + 24 + (1 + 1 + 72 + 1 + 33) / 4;
|
|
76
73
|
}
|
|
77
74
|
throw new Error('unknown address type');
|
|
78
75
|
}
|
|
79
|
-
function getUtxoDust(addressType) {
|
|
80
|
-
if (addressType ===
|
|
76
|
+
export function getUtxoDust(addressType) {
|
|
77
|
+
if (addressType === AddressType.P2WPKH || addressType === AddressType.M44_P2WPKH) {
|
|
81
78
|
return 294;
|
|
82
79
|
}
|
|
83
|
-
else if (addressType ===
|
|
80
|
+
else if (addressType === AddressType.P2TR || addressType === AddressType.M44_P2TR) {
|
|
84
81
|
return 330;
|
|
85
82
|
}
|
|
86
83
|
else {
|
|
87
84
|
return 546;
|
|
88
85
|
}
|
|
89
86
|
}
|
|
90
|
-
exports.getUtxoDust = getUtxoDust;
|
|
91
87
|
// deprecated
|
|
92
88
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
93
|
-
function getAddressUtxoDust(address, networkType =
|
|
94
|
-
return
|
|
89
|
+
export function getAddressUtxoDust(address, networkType = NetworkType.MAINNET) {
|
|
90
|
+
return decodeAddress(address).dust;
|
|
95
91
|
}
|
|
96
|
-
|
|
97
|
-
exports.utxoHelper = {
|
|
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,66 +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 = void 0;
|
|
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
|
}
|
|
66
|
-
exports.sendAtomicalsFT = sendAtomicalsFT;
|
|
@@ -1,45 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
tx.setFeeRate(feeRate);
|
|
31
|
-
tx.setEnableRBF(enableRBF);
|
|
32
|
-
tx.setChangeAddress(changeAddress);
|
|
33
|
-
const toSignInputs = [];
|
|
34
|
-
// add asset
|
|
35
|
-
tx.addInput(assetUtxo);
|
|
36
|
-
toSignInputs.push({ index: 0, publicKey: assetUtxo.pubkey });
|
|
37
|
-
tx.addOutput(toAddress, assetUtxo.satoshis);
|
|
38
|
-
// add btc
|
|
39
|
-
const _toSignInputs = yield tx.addSufficientUtxosForFee(btcUtxos, true);
|
|
40
|
-
toSignInputs.push(..._toSignInputs);
|
|
41
|
-
const psbt = tx.toPsbt();
|
|
42
|
-
return { psbt, toSignInputs };
|
|
43
|
-
});
|
|
1
|
+
import { ErrorCodes, WalletUtilsError } from '../error';
|
|
2
|
+
import { Transaction, utxoHelper } from '../transaction';
|
|
3
|
+
export async function sendAtomicalsNFT(params) {
|
|
4
|
+
const { assetUtxo, btcUtxos, toAddress, networkType, changeAddress, feeRate, enableRBF = true } = params;
|
|
5
|
+
// safe check
|
|
6
|
+
if (utxoHelper.hasAtomicalsFT([assetUtxo]) || utxoHelper.hasInscription([assetUtxo])) {
|
|
7
|
+
throw new WalletUtilsError(ErrorCodes.NOT_SAFE_UTXOS);
|
|
8
|
+
}
|
|
9
|
+
if (utxoHelper.hasAnyAssets(btcUtxos)) {
|
|
10
|
+
throw new WalletUtilsError(ErrorCodes.NOT_SAFE_UTXOS);
|
|
11
|
+
}
|
|
12
|
+
if (assetUtxo.atomicals.length !== 1) {
|
|
13
|
+
throw new WalletUtilsError(ErrorCodes.NOT_SAFE_UTXOS);
|
|
14
|
+
}
|
|
15
|
+
const tx = new Transaction();
|
|
16
|
+
tx.setNetworkType(networkType);
|
|
17
|
+
tx.setFeeRate(feeRate);
|
|
18
|
+
tx.setEnableRBF(enableRBF);
|
|
19
|
+
tx.setChangeAddress(changeAddress);
|
|
20
|
+
const toSignInputs = [];
|
|
21
|
+
// add asset
|
|
22
|
+
tx.addInput(assetUtxo);
|
|
23
|
+
toSignInputs.push({ index: 0, publicKey: assetUtxo.pubkey });
|
|
24
|
+
tx.addOutput(toAddress, assetUtxo.satoshis);
|
|
25
|
+
// add btc
|
|
26
|
+
const _toSignInputs = await tx.addSufficientUtxosForFee(btcUtxos, true);
|
|
27
|
+
toSignInputs.push(..._toSignInputs);
|
|
28
|
+
const psbt = tx.toPsbt();
|
|
29
|
+
return { psbt, toSignInputs };
|
|
44
30
|
}
|
|
45
|
-
exports.sendAtomicalsNFT = sendAtomicalsNFT;
|