@teleportdao/bitcoin 3.0.0 → 4.0.0-alpha.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.
- package/dist/bitcoin-interface-ordinal.d.ts +24 -24
- package/dist/bitcoin-interface-ordinal.d.ts.map +1 -1
- package/dist/bitcoin-interface-ordinal.js +89 -107
- package/dist/bitcoin-interface-ordinal.js.map +1 -1
- package/dist/bitcoin-interface-teleswap.d.ts +2 -2
- package/dist/bitcoin-interface-teleswap.d.ts.map +1 -1
- package/dist/bitcoin-interface-teleswap.js +77 -88
- package/dist/bitcoin-interface-teleswap.js.map +1 -1
- package/dist/bitcoin-interface-utils.d.ts +7 -4
- package/dist/bitcoin-interface-utils.d.ts.map +1 -1
- package/dist/bitcoin-interface-utils.js +11 -5
- package/dist/bitcoin-interface-utils.js.map +1 -1
- package/dist/bitcoin-interface-wallet.d.ts +1 -0
- package/dist/bitcoin-interface-wallet.d.ts.map +1 -1
- package/dist/bitcoin-interface-wallet.js +87 -95
- package/dist/bitcoin-interface-wallet.js.map +1 -1
- package/dist/bitcoin-interface.d.ts.map +1 -1
- package/dist/bitcoin-interface.js +58 -87
- package/dist/bitcoin-interface.js.map +1 -1
- package/dist/bitcoin-utils.d.ts +7 -4
- package/dist/bitcoin-utils.d.ts.map +1 -1
- package/dist/bitcoin-utils.js +93 -54
- package/dist/bitcoin-utils.js.map +1 -1
- package/dist/bitcoin-wallet-base.d.ts +23 -11
- package/dist/bitcoin-wallet-base.d.ts.map +1 -1
- package/dist/bitcoin-wallet-base.js +148 -138
- package/dist/bitcoin-wallet-base.js.map +1 -1
- package/dist/helper/brc20-helper.d.ts.map +1 -1
- package/dist/helper/brc20-helper.js +4 -6
- package/dist/helper/brc20-helper.js.map +1 -1
- package/dist/helper/index.js +17 -7
- package/dist/helper/index.js.map +1 -1
- package/dist/helper/ordinal-helper.d.ts +3 -9
- package/dist/helper/ordinal-helper.d.ts.map +1 -1
- package/dist/helper/ordinal-helper.js +20 -85
- package/dist/helper/ordinal-helper.js.map +1 -1
- package/dist/helper/teleswap-helper.d.ts.map +1 -1
- package/dist/helper/teleswap-helper.js +13 -12
- package/dist/helper/teleswap-helper.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -7
- package/dist/index.js.map +1 -1
- package/dist/multisig-wallet-helper.d.ts +14 -1
- package/dist/multisig-wallet-helper.d.ts.map +1 -1
- package/dist/multisig-wallet-helper.js +135 -149
- package/dist/multisig-wallet-helper.js.map +1 -1
- package/dist/ordinal-wallet.d.ts +27 -19
- package/dist/ordinal-wallet.d.ts.map +1 -1
- package/dist/ordinal-wallet.js +263 -293
- package/dist/ordinal-wallet.js.map +1 -1
- package/dist/sign/sign-transaction.d.ts +5 -2
- package/dist/sign/sign-transaction.d.ts.map +1 -1
- package/dist/sign/sign-transaction.js +32 -39
- package/dist/sign/sign-transaction.js.map +1 -1
- package/dist/teleswap-wallet.d.ts +1 -0
- package/dist/teleswap-wallet.d.ts.map +1 -1
- package/dist/teleswap-wallet.js +40 -53
- package/dist/teleswap-wallet.js.map +1 -1
- package/dist/transaction-builder/bitcoin-transaction-builder.js +21 -21
- package/dist/transaction-builder/bitcoin-transaction-builder.js.map +1 -1
- package/dist/transaction-builder/coin-select.d.ts +19 -3
- package/dist/transaction-builder/coin-select.d.ts.map +1 -1
- package/dist/transaction-builder/coin-select.js +193 -181
- package/dist/transaction-builder/coin-select.js.map +1 -1
- package/dist/transaction-builder/index.d.ts +1 -0
- package/dist/transaction-builder/index.d.ts.map +1 -1
- package/dist/transaction-builder/index.js +1 -0
- package/dist/transaction-builder/index.js.map +1 -1
- package/dist/transaction-builder/ordinal-transaction-builder.d.ts +4 -4
- package/dist/transaction-builder/ordinal-transaction-builder.d.ts.map +1 -1
- package/dist/transaction-builder/ordinal-transaction-builder.js +51 -48
- package/dist/transaction-builder/ordinal-transaction-builder.js.map +1 -1
- package/dist/transaction-builder/transaction-builder.d.ts +57 -54
- package/dist/transaction-builder/transaction-builder.d.ts.map +1 -1
- package/dist/transaction-builder/transaction-builder.js +394 -308
- package/dist/transaction-builder/transaction-builder.js.map +1 -1
- package/dist/utils/networks.js +17 -7
- package/dist/utils/networks.js.map +1 -1
- package/dist/utils/tools.js +24 -35
- package/dist/utils/tools.js.map +1 -1
- package/package.json +4 -4
- package/src/bitcoin-interface-utils.ts +17 -8
- package/src/bitcoin-interface-wallet.ts +15 -1
- package/src/bitcoin-utils.ts +52 -3
- package/src/bitcoin-wallet-base.ts +67 -23
- package/src/helper/ordinal-helper.ts +0 -83
- package/src/index.ts +2 -0
- package/src/multisig-wallet-helper.ts +296 -0
- package/src/sign/sign-transaction.ts +5 -7
- package/src/transaction-builder/coin-select.ts +633 -0
- package/src/transaction-builder/index.ts +1 -0
- package/src/transaction-builder/transaction-builder.ts +424 -279
- package/dist/bitcoin-wallet-base copy.d.ts +0 -122
- package/dist/bitcoin-wallet-base copy.d.ts.map +0 -1
- package/dist/bitcoin-wallet-base copy.js +0 -279
- package/dist/bitcoin-wallet-base copy.js.map +0 -1
- package/dist/multisig-coordinator-wallet.d.ts +0 -2
- package/dist/multisig-coordinator-wallet.d.ts.map +0 -1
- package/dist/multisig-coordinator-wallet.js +0 -6
- package/dist/multisig-coordinator-wallet.js.map +0 -1
- package/dist/multisig-wallet.d.ts +0 -20
- package/dist/multisig-wallet.d.ts.map +0 -1
- package/dist/multisig-wallet.js +0 -119
- package/dist/multisig-wallet.js.map +0 -1
|
@@ -15,66 +15,54 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
34
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.BaseTransactionBuilder =
|
|
36
|
+
exports.BaseTransactionBuilder = void 0;
|
|
36
37
|
const bitcoin = __importStar(require("bitcoinjs-lib"));
|
|
37
38
|
const bitcoin_utils_1 = require("../bitcoin-utils");
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
exports.componentBytes = {
|
|
42
|
-
bytePerInput: {
|
|
43
|
-
p2pkh: 148,
|
|
44
|
-
p2wpkh: 68,
|
|
45
|
-
"p2sh-p2wpkh": 91,
|
|
46
|
-
p2tr: 58,
|
|
47
|
-
default: 100,
|
|
48
|
-
},
|
|
49
|
-
baseTxBytes: 10 + 5,
|
|
50
|
-
bytePerOutput: {
|
|
51
|
-
p2pkh: 34,
|
|
52
|
-
p2wpkh: 31,
|
|
53
|
-
p2sh: 32,
|
|
54
|
-
p2tr: 43,
|
|
55
|
-
default: 35,
|
|
56
|
-
max: 45,
|
|
57
|
-
},
|
|
58
|
-
scriptExtraBytes: {
|
|
59
|
-
lessThan255: 12,
|
|
60
|
-
moreThan255: 15,
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
exports.DUST = 1000;
|
|
64
|
-
function coinSelectInOrder(utxos, outputs, feeRate) {
|
|
65
|
-
let response = coinselectAccumulative(utxos, outputs, 1);
|
|
66
|
-
return Object.assign(Object.assign({}, response), { fee: +(+response.fee * feeRate).toFixed() });
|
|
67
|
-
}
|
|
39
|
+
const coin_select_1 = require("./coin-select");
|
|
40
|
+
const SINGLESIG_TYPES = ["p2pkh", "p2wpkh", "p2sh-p2wpkh", "p2tr"];
|
|
41
|
+
const MULTISIG_TYPES = ["p2sh", "p2wsh", "p2sh-p2wsh"];
|
|
68
42
|
class BaseTransactionBuilder {
|
|
43
|
+
MULTISIG_TYPES = MULTISIG_TYPES;
|
|
44
|
+
testnet;
|
|
45
|
+
network;
|
|
46
|
+
maximumNumberOfOutputsInTransaction;
|
|
47
|
+
feeMin;
|
|
48
|
+
dustLimit;
|
|
49
|
+
NO_RBF_SEQUENCE = 0xffffffff;
|
|
69
50
|
constructor({ network, testnet, feeMin = 0, dustLimit, maximumNumberOfOutputsInTransaction = 50, }) {
|
|
70
|
-
this.NO_RBF_SEQUENCE = 0xffffffff;
|
|
71
51
|
this.testnet = testnet;
|
|
72
52
|
this.network = network;
|
|
73
53
|
this.maximumNumberOfOutputsInTransaction = maximumNumberOfOutputsInTransaction;
|
|
74
54
|
this.feeMin = feeMin;
|
|
75
|
-
this.dustLimit = dustLimit || 1 * 2 *
|
|
55
|
+
this.dustLimit = dustLimit || 1 * 2 * coin_select_1.componentBytes.bytePerInput.p2pkh;
|
|
56
|
+
}
|
|
57
|
+
isMultiSig(addressType) {
|
|
58
|
+
return this.MULTISIG_TYPES.includes(addressType);
|
|
76
59
|
}
|
|
77
60
|
createAddressObject(input) {
|
|
61
|
+
if (this.MULTISIG_TYPES.includes(input.addressType))
|
|
62
|
+
return (0, bitcoin_utils_1.createMultisigAddressObjectByPublicKeys)(input.addressType, {
|
|
63
|
+
publicKeys: input.publicKeys,
|
|
64
|
+
numberOfSigners: input.numberOfSigners,
|
|
65
|
+
});
|
|
78
66
|
return (0, bitcoin_utils_1.createAddressObjectByPublicKey)(input, this.network);
|
|
79
67
|
}
|
|
80
68
|
validateAddress(address) {
|
|
@@ -99,77 +87,32 @@ class BaseTransactionBuilder {
|
|
|
99
87
|
};
|
|
100
88
|
}
|
|
101
89
|
calculateTxSize(inputTypes, outputs, changeAddressType = "default") {
|
|
102
|
-
|
|
103
|
-
const outputSizes = outputs.map((outP) => {
|
|
104
|
-
if (outP.address) {
|
|
105
|
-
let addressType = "default";
|
|
106
|
-
try {
|
|
107
|
-
addressType = (0, bitcoin_utils_1.getAddressType)(outP.address, this.network);
|
|
108
|
-
}
|
|
109
|
-
catch (_a) {
|
|
110
|
-
addressType = "default";
|
|
111
|
-
}
|
|
112
|
-
return exports.componentBytes.bytePerOutput[addressType];
|
|
113
|
-
}
|
|
114
|
-
if (outP.script) {
|
|
115
|
-
if (outP.script.byteLength < 255) {
|
|
116
|
-
return outP.script.byteLength + exports.componentBytes.scriptExtraBytes.lessThan255;
|
|
117
|
-
}
|
|
118
|
-
return outP.script.byteLength + exports.componentBytes.scriptExtraBytes.moreThan255;
|
|
119
|
-
}
|
|
120
|
-
return exports.componentBytes.bytePerOutput[changeAddressType];
|
|
121
|
-
});
|
|
122
|
-
const txSize = exports.componentBytes.baseTxBytes +
|
|
123
|
-
inputsSizes.reduce((a, c) => a + c, 0) +
|
|
124
|
-
outputSizes.reduce((a, c) => a + c, 0);
|
|
125
|
-
return txSize;
|
|
90
|
+
return (0, coin_select_1.calculateTxSize)(inputTypes, outputs, changeAddressType, this.network);
|
|
126
91
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
break;
|
|
136
|
-
case "accumulative":
|
|
137
|
-
selectResponse = coinselectAccumulative(filteredUtxo, targets, Math.round(feeRate));
|
|
138
|
-
break;
|
|
139
|
-
case "inOrder":
|
|
140
|
-
selectResponse = coinSelectInOrder(filteredUtxo, targets, Math.round(feeRate));
|
|
141
|
-
break;
|
|
142
|
-
case "full":
|
|
143
|
-
if (!targets[0].address) {
|
|
144
|
-
throw new Error();
|
|
145
|
-
}
|
|
146
|
-
selectResponse = coinselectSplit(filteredUtxo, [{ address: targets[0].address }], Math.round(feeRate));
|
|
147
|
-
break;
|
|
148
|
-
default:
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
let { inputs, outputs, fee, } = selectResponse;
|
|
152
|
-
if (!inputs || !outputs) {
|
|
153
|
-
inputs = filteredUtxo;
|
|
154
|
-
outputs = targets;
|
|
155
|
-
fee = inputs.reduce((a, b) => a + b.value, 0) - outputs.reduce((a, b) => a + b.value, 0);
|
|
156
|
-
}
|
|
157
|
-
let changeAddressType = "default";
|
|
158
|
-
try {
|
|
159
|
-
changeAddressType = (0, bitcoin_utils_1.getAddressType)((changeObject === null || changeObject === void 0 ? void 0 : changeObject.address) || "", this.network);
|
|
160
|
-
}
|
|
161
|
-
catch (_a) {
|
|
162
|
-
changeAddressType = "default";
|
|
92
|
+
oldTxFeeCheck(newInputs, newOutputs, newChange, newFee, changeObject, feeRate, selectType, changeAddressType) {
|
|
93
|
+
let inputs = newInputs.slice();
|
|
94
|
+
let outputs = newOutputs.slice();
|
|
95
|
+
let fee = newFee;
|
|
96
|
+
if (newChange) {
|
|
97
|
+
outputs.push({
|
|
98
|
+
value: newChange.value,
|
|
99
|
+
});
|
|
163
100
|
}
|
|
164
|
-
const txSize = this.calculateTxSize(inputs.map((i) =>
|
|
101
|
+
const txSize = this.calculateTxSize(inputs.map((i) => ({
|
|
102
|
+
addressType: i.signerInfo.addressType,
|
|
103
|
+
m: i.signerInfo.publicKeys?.length,
|
|
104
|
+
n: i.signerInfo.numberOfSigners,
|
|
105
|
+
})), outputs, changeAddressType);
|
|
106
|
+
let extraChangeFee = Math.round(coin_select_1.componentBytes.bytePerOutput.default * feeRate);
|
|
165
107
|
let txFee = Math.round(txSize * feeRate);
|
|
166
|
-
if (
|
|
167
|
-
txFee = Math.round(
|
|
108
|
+
if (feeRate === 1) {
|
|
109
|
+
txFee = Math.round(1.1 * txFee);
|
|
168
110
|
}
|
|
169
111
|
if (inputs.reduce((a, b) => a + b.value, 0) -
|
|
170
112
|
outputs.filter((o) => o.address || o.script).reduce((a, b) => a + b.value, 0) -
|
|
171
|
-
txFee
|
|
172
|
-
|
|
113
|
+
txFee -
|
|
114
|
+
extraChangeFee <
|
|
115
|
+
-1 * coin_select_1.DUST) {
|
|
173
116
|
let spendableBalance = inputs.reduce((a, b) => a + b.value, 0);
|
|
174
117
|
let totalOutputAmount = outputs
|
|
175
118
|
.filter((o) => o.address || o.script)
|
|
@@ -178,131 +121,293 @@ class BaseTransactionBuilder {
|
|
|
178
121
|
throw new Error(`not enough balance. details: ${JSON.stringify({ spendableBalance, totalOutputAmount, txFee, need }, null, 2)}`);
|
|
179
122
|
}
|
|
180
123
|
let diff = fee - txFee;
|
|
181
|
-
|
|
124
|
+
if (Math.abs(diff) >= coin_select_1.DUST) {
|
|
125
|
+
console.log("diff", diff, "fee", fee, "txFee", txFee);
|
|
126
|
+
}
|
|
127
|
+
let changeIndex = outputs.findIndex((x) => !x?.address && !x.script && (x.value || 0) > 0);
|
|
182
128
|
let change;
|
|
183
|
-
if (
|
|
129
|
+
if (diff > 0) {
|
|
184
130
|
if (changeIndex >= 0) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
outputs[0].value = outputs[0].value + diff;
|
|
131
|
+
if (!changeObject)
|
|
132
|
+
throw new Error("change not exist");
|
|
133
|
+
change = {
|
|
134
|
+
address: changeObject.address,
|
|
135
|
+
value: outputs[changeIndex].value + diff,
|
|
136
|
+
};
|
|
192
137
|
fee = fee - diff;
|
|
193
138
|
}
|
|
194
|
-
else {
|
|
139
|
+
else if (diff - extraChangeFee > coin_select_1.DUST) {
|
|
195
140
|
if (!changeObject)
|
|
196
141
|
throw new Error("change not exist");
|
|
197
142
|
change = {
|
|
198
143
|
address: changeObject.address,
|
|
199
|
-
value:
|
|
144
|
+
value: diff - extraChangeFee,
|
|
200
145
|
};
|
|
201
|
-
fee = fee - diff;
|
|
146
|
+
fee = fee - diff + extraChangeFee;
|
|
202
147
|
}
|
|
203
|
-
|
|
204
|
-
|
|
148
|
+
}
|
|
149
|
+
else if (-1 * diff > 0) {
|
|
150
|
+
const positiveDiff = -1 * diff;
|
|
151
|
+
let currentChangeValue = changeIndex > 0 ? outputs[changeIndex].value : -1 * extraChangeFee;
|
|
152
|
+
if (currentChangeValue - positiveDiff < -1 * coin_select_1.DUST) {
|
|
153
|
+
throw new Error(`not enough balance.`);
|
|
154
|
+
}
|
|
155
|
+
if (changeIndex > 0) {
|
|
156
|
+
if (!changeObject)
|
|
157
|
+
throw new Error("change not exist");
|
|
158
|
+
change =
|
|
159
|
+
outputs[changeIndex].value - positiveDiff > coin_select_1.DUST
|
|
160
|
+
? {
|
|
161
|
+
address: changeObject.address,
|
|
162
|
+
value: outputs[changeIndex].value - positiveDiff,
|
|
163
|
+
}
|
|
164
|
+
: undefined;
|
|
165
|
+
fee = fee + positiveDiff;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (changeIndex > 0) {
|
|
169
|
+
if (!changeObject)
|
|
170
|
+
throw new Error("change not exist");
|
|
171
|
+
change = {
|
|
172
|
+
address: changeObject.address,
|
|
173
|
+
value: outputs[changeIndex].value,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (changeIndex >= 0) {
|
|
177
|
+
outputs.splice(changeIndex, 1);
|
|
178
|
+
}
|
|
179
|
+
if (Math.abs(fee - newFee) > coin_select_1.DUST) {
|
|
180
|
+
console.log("fee", fee);
|
|
181
|
+
console.log("newFee", newFee);
|
|
182
|
+
throw new Error("fee mismatch");
|
|
183
|
+
}
|
|
184
|
+
let totalOutputValue = outputs.reduce((a, b) => a + b.value, 0);
|
|
185
|
+
let totalNewOutputValue = newOutputs.reduce((a, b) => a + b.value, 0);
|
|
186
|
+
if (totalOutputValue - totalNewOutputValue !== 0) {
|
|
187
|
+
console.log("totalOutputValue", totalOutputValue);
|
|
188
|
+
console.log("totalNewOutputValue", totalNewOutputValue);
|
|
189
|
+
console.log("diff", totalOutputValue - totalNewOutputValue);
|
|
190
|
+
throw new Error("output value mismatch");
|
|
191
|
+
}
|
|
192
|
+
if (outputs.length !== newOutputs.length) {
|
|
193
|
+
console.log("outputs", outputs);
|
|
194
|
+
console.log("newOutputs", newOutputs);
|
|
195
|
+
throw new Error("output length mismatch");
|
|
196
|
+
}
|
|
197
|
+
for (let i = 0; i < outputs.length; i += 1) {
|
|
198
|
+
if (outputs[i].value !== newOutputs[i].value) {
|
|
199
|
+
console.log("outputs[i].value", outputs[i].value);
|
|
200
|
+
console.log("newOutputs[i].value", newOutputs[i].value);
|
|
201
|
+
throw new Error("output value mismatch");
|
|
202
|
+
}
|
|
203
|
+
if (outputs[i].address !== newOutputs[i].address) {
|
|
204
|
+
console.log("outputs[i].address", outputs[i].address);
|
|
205
|
+
console.log("newOutputs[i].address", newOutputs[i].address);
|
|
206
|
+
throw new Error("output address mismatch");
|
|
207
|
+
}
|
|
208
|
+
if (outputs[i].script !== newOutputs[i].script) {
|
|
209
|
+
console.log("outputs[i].script", outputs[i].script);
|
|
210
|
+
console.log("newOutputs[i].script", newOutputs[i].script);
|
|
211
|
+
throw new Error("output script mismatch");
|
|
205
212
|
}
|
|
206
213
|
}
|
|
214
|
+
let totalInputValue = inputs.reduce((a, b) => a + b.value, 0);
|
|
215
|
+
let totalNewInputValue = newInputs.reduce((a, b) => a + b.value, 0);
|
|
216
|
+
if (Math.abs(totalInputValue - (change?.value || 0) - (totalNewInputValue - (newChange?.value || 0))) > coin_select_1.DUST) {
|
|
217
|
+
console.log("totalInputValue", totalInputValue);
|
|
218
|
+
throw new Error("input value mismatch");
|
|
219
|
+
}
|
|
220
|
+
return { inputs, outputs, change, fee };
|
|
221
|
+
}
|
|
222
|
+
helperHandleInputsAndOutputs({ requiredUtxo, targets, extendedUtxo, feeRate, changeObject, selectType = "normal", }) {
|
|
223
|
+
const filteredUtxo = selectType !== "inOrder"
|
|
224
|
+
? extendedUtxo.filter((u) => u.value >
|
|
225
|
+
+feeRate *
|
|
226
|
+
(0, coin_select_1.getInputSize)(u.signerInfo.addressType, {
|
|
227
|
+
m: u.signerInfo.publicKeys?.length,
|
|
228
|
+
n: u.signerInfo.numberOfSigners,
|
|
229
|
+
}) +
|
|
230
|
+
coin_select_1.DUST)
|
|
231
|
+
: extendedUtxo;
|
|
232
|
+
let changeAddressType = "default";
|
|
233
|
+
try {
|
|
234
|
+
changeAddressType = (0, bitcoin_utils_1.getAddressType)(changeObject.address || "", this.network);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
changeAddressType = "default";
|
|
238
|
+
}
|
|
239
|
+
let selectResponse;
|
|
240
|
+
let newFeeRate = feeRate === 1 ? 1.1 : feeRate;
|
|
241
|
+
switch (selectType) {
|
|
242
|
+
case "normal":
|
|
243
|
+
selectResponse = (0, coin_select_1.coinSelectNormal)(filteredUtxo, targets, newFeeRate, changeAddressType, this.network, 5, requiredUtxo, {
|
|
244
|
+
minInputCount: 10,
|
|
245
|
+
maxInputValue: 0.003 * 1e8,
|
|
246
|
+
});
|
|
247
|
+
break;
|
|
248
|
+
case "inOrder":
|
|
249
|
+
selectResponse = (0, coin_select_1.coinSelectAccumulative)(filteredUtxo, targets, newFeeRate, changeAddressType, this.network);
|
|
250
|
+
break;
|
|
251
|
+
case "full":
|
|
252
|
+
selectResponse = (0, coin_select_1.coinSelectAll)(filteredUtxo, targets, newFeeRate, changeAddressType, this.network);
|
|
253
|
+
break;
|
|
254
|
+
default:
|
|
255
|
+
throw new Error("invalid select type");
|
|
256
|
+
}
|
|
257
|
+
let { success, inputs, outputs, change: changeValue, fee, totalInputValue, totalOutputValue, needed, } = selectResponse;
|
|
258
|
+
let change;
|
|
259
|
+
if (changeValue) {
|
|
260
|
+
change = {
|
|
261
|
+
address: changeObject.address,
|
|
262
|
+
value: changeValue.value,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (!success || needed < 0) {
|
|
266
|
+
throw new Error(`not enough balance. details: ${JSON.stringify({ totalInputValue, totalOutputValue, fee, needed }, null, 2)}`);
|
|
267
|
+
}
|
|
268
|
+
this.oldTxFeeCheck(inputs, outputs, change, fee, changeObject, feeRate, selectType, changeAddressType);
|
|
207
269
|
return {
|
|
208
270
|
inputs,
|
|
209
271
|
fee,
|
|
210
|
-
outputs
|
|
272
|
+
outputs,
|
|
211
273
|
change,
|
|
212
274
|
};
|
|
213
275
|
}
|
|
214
|
-
filterAndConvertTxDataToStandardFormat({ extendedUtxo, targets, changeObject, feeRate, selectType, }) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
});
|
|
223
|
-
let inputs = yield this.convertExtendedUtxoToInputs(filteredInputs);
|
|
224
|
-
return {
|
|
225
|
-
inputs,
|
|
226
|
-
outputs,
|
|
227
|
-
change,
|
|
228
|
-
fee,
|
|
229
|
-
feeRate,
|
|
230
|
-
};
|
|
276
|
+
async filterAndConvertTxDataToStandardFormat({ extendedUtxo, requiredUtxo, targets, changeObject, feeRate, selectType, }) {
|
|
277
|
+
let { inputs: filteredInputs, outputs, change, fee, } = this.helperHandleInputsAndOutputs({
|
|
278
|
+
requiredUtxo,
|
|
279
|
+
targets,
|
|
280
|
+
extendedUtxo,
|
|
281
|
+
feeRate,
|
|
282
|
+
changeObject,
|
|
283
|
+
selectType,
|
|
231
284
|
});
|
|
285
|
+
let inputs = await this.convertExtendedUtxoToInputs(filteredInputs);
|
|
286
|
+
return {
|
|
287
|
+
inputs,
|
|
288
|
+
outputs,
|
|
289
|
+
change,
|
|
290
|
+
fee,
|
|
291
|
+
feeRate,
|
|
292
|
+
};
|
|
232
293
|
}
|
|
233
|
-
convertExtendedUtxoToInputs(baseInputs = []) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
294
|
+
async convertExtendedUtxoToInputs(baseInputs = []) {
|
|
295
|
+
let inputs = baseInputs;
|
|
296
|
+
const transactionHex = {};
|
|
297
|
+
for (let i in inputs) {
|
|
298
|
+
let { address, publicKey, derivationPath, masterFingerprint, addressType, publicKeys, numberOfSigners, } = inputs[i].signerInfo;
|
|
299
|
+
let addressObject = this.createAddressObject({
|
|
300
|
+
publicKey: Buffer.from(publicKey, "hex"),
|
|
301
|
+
publicKeys: publicKeys?.map((p) => Buffer.from(p, "hex")),
|
|
302
|
+
numberOfSigners,
|
|
303
|
+
addressType,
|
|
304
|
+
});
|
|
305
|
+
if (derivationPath && masterFingerprint && addressObject.pubkey) {
|
|
306
|
+
inputs[i].bip32Derivation = [
|
|
307
|
+
{
|
|
308
|
+
path: derivationPath,
|
|
309
|
+
pubkey: addressObject.pubkey,
|
|
310
|
+
masterFingerprint: Buffer.from(masterFingerprint, "hex"),
|
|
311
|
+
},
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
if (addressType === "p2pkh") {
|
|
315
|
+
const txHex = transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash));
|
|
316
|
+
transactionHex[inputs[i].hash] = txHex;
|
|
317
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
|
|
318
|
+
}
|
|
319
|
+
else if (addressType === "p2wpkh") {
|
|
320
|
+
if (!addressObject.output)
|
|
321
|
+
throw new Error("invalid signer info");
|
|
322
|
+
inputs[i].witnessUtxo = {
|
|
323
|
+
script: addressObject.output,
|
|
324
|
+
value: inputs[i].value,
|
|
325
|
+
};
|
|
326
|
+
if (inputs[i].signerInfo.includeHex) {
|
|
327
|
+
const txHex = transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash));
|
|
328
|
+
transactionHex[inputs[i].hash] = txHex;
|
|
329
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
|
|
252
330
|
}
|
|
253
|
-
|
|
254
|
-
|
|
331
|
+
}
|
|
332
|
+
else if (addressType === "p2sh-p2wpkh") {
|
|
333
|
+
if (!addressObject.output)
|
|
334
|
+
throw new Error("invalid signer info");
|
|
335
|
+
inputs[i].witnessUtxo = {
|
|
336
|
+
script: addressObject.output,
|
|
337
|
+
value: inputs[i].value,
|
|
338
|
+
};
|
|
339
|
+
if (!addressObject?.redeem?.output)
|
|
340
|
+
throw new Error("invalid signer info for p2sh-p2wpkh address");
|
|
341
|
+
inputs[i].redeemScript = addressObject.redeem.output;
|
|
342
|
+
if (inputs[i].signerInfo.includeHex) {
|
|
343
|
+
const txHex = transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash));
|
|
255
344
|
transactionHex[inputs[i].hash] = txHex;
|
|
256
345
|
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
|
|
257
346
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
347
|
+
}
|
|
348
|
+
else if (addressType === "p2tr") {
|
|
349
|
+
if (!addressObject.output)
|
|
350
|
+
throw new Error("invalid signer info");
|
|
351
|
+
inputs[i].witnessUtxo = {
|
|
352
|
+
script: addressObject.output,
|
|
353
|
+
value: inputs[i].value,
|
|
354
|
+
};
|
|
355
|
+
if (!addressObject.pubkey)
|
|
356
|
+
throw new Error("invalid signer info for p2tr address (pubkey)");
|
|
357
|
+
inputs[i].tapInternalKey = addressObject.internalPubkey;
|
|
358
|
+
if (inputs[i].signerInfo.includeHex) {
|
|
359
|
+
const txHex = transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash));
|
|
360
|
+
transactionHex[inputs[i].hash] = txHex;
|
|
361
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
|
|
270
362
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
363
|
+
}
|
|
364
|
+
else if (addressType === "p2sh") {
|
|
365
|
+
const txHex = transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash));
|
|
366
|
+
transactionHex[inputs[i].hash] = txHex;
|
|
367
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
|
|
368
|
+
if (!addressObject.output)
|
|
369
|
+
throw new Error("invalid signer info");
|
|
370
|
+
if (!addressObject?.redeem?.output)
|
|
371
|
+
throw new Error("invalid signer info for p2sh address");
|
|
372
|
+
inputs[i].redeemScript = addressObject.redeem.output;
|
|
373
|
+
}
|
|
374
|
+
else if (addressType === "p2wsh") {
|
|
375
|
+
if (!addressObject.output)
|
|
376
|
+
throw new Error("invalid signer info");
|
|
377
|
+
inputs[i].witnessUtxo = {
|
|
378
|
+
script: addressObject.output,
|
|
379
|
+
value: inputs[i].value,
|
|
380
|
+
};
|
|
381
|
+
if (!addressObject?.redeem?.output)
|
|
382
|
+
throw new Error("invalid signer info for p2wsh address");
|
|
383
|
+
inputs[i].witnessScript = addressObject.redeem?.output;
|
|
384
|
+
if (inputs[i].signerInfo.includeHex) {
|
|
385
|
+
const txHex = transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash));
|
|
386
|
+
transactionHex[inputs[i].hash] = txHex;
|
|
387
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
|
|
286
388
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
389
|
+
}
|
|
390
|
+
else if (addressType === "p2sh-p2wsh") {
|
|
391
|
+
if (!addressObject.output)
|
|
392
|
+
throw new Error("invalid signer info");
|
|
393
|
+
inputs[i].witnessUtxo = {
|
|
394
|
+
script: addressObject.output,
|
|
395
|
+
value: inputs[i].value,
|
|
396
|
+
};
|
|
397
|
+
if (!addressObject?.redeem?.output)
|
|
398
|
+
throw new Error("invalid signer info for p2sh address");
|
|
399
|
+
inputs[i].redeemScript = addressObject.redeem.output;
|
|
400
|
+
if (!addressObject?.redeem?.redeem?.output)
|
|
401
|
+
throw new Error("invalid signer info for p2sh-p2wsh address");
|
|
402
|
+
inputs[i].witnessScript = addressObject.redeem.redeem.output;
|
|
403
|
+
if (inputs[i].signerInfo.includeHex) {
|
|
404
|
+
const txHex = transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash));
|
|
405
|
+
transactionHex[inputs[i].hash] = txHex;
|
|
406
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
|
|
302
407
|
}
|
|
303
408
|
}
|
|
304
|
-
|
|
305
|
-
|
|
409
|
+
}
|
|
410
|
+
return inputs;
|
|
306
411
|
}
|
|
307
412
|
createUnsignedTransaction({ inputs, outputs, change, fee, feeRate, sequenceNumber, }) {
|
|
308
413
|
const sequence = sequenceNumber || this.NO_RBF_SEQUENCE - 2;
|
|
@@ -310,88 +415,55 @@ class BaseTransactionBuilder {
|
|
|
310
415
|
const newPsbt = new bitcoin.Psbt({ network });
|
|
311
416
|
newPsbt.setMaximumFeeRate(+(feeRate + feeRate / 100).toFixed());
|
|
312
417
|
for (const input of inputs) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (!i.bip32Derivation)
|
|
338
|
-
delete i.bip32Derivation;
|
|
339
|
-
if (!i.nonWitnessUtxo)
|
|
340
|
-
delete i.nonWitnessUtxo;
|
|
341
|
-
newPsbt.addInput(i);
|
|
342
|
-
break;
|
|
343
|
-
}
|
|
344
|
-
case "p2sh-p2wpkh": {
|
|
345
|
-
let i = {
|
|
346
|
-
hash: input.hash,
|
|
347
|
-
index: Number(input.index),
|
|
348
|
-
witnessUtxo: input.witnessUtxo,
|
|
349
|
-
nonWitnessUtxo: input.nonWitnessUtxo,
|
|
350
|
-
redeemScript: input.redeemScript,
|
|
351
|
-
sequence,
|
|
352
|
-
bip32Derivation: input.bip32Derivation,
|
|
353
|
-
};
|
|
354
|
-
if (!i.bip32Derivation)
|
|
355
|
-
delete i.bip32Derivation;
|
|
356
|
-
if (!i.nonWitnessUtxo)
|
|
357
|
-
delete i.nonWitnessUtxo;
|
|
358
|
-
newPsbt.addInput(i);
|
|
359
|
-
break;
|
|
360
|
-
}
|
|
361
|
-
case "p2tr": {
|
|
362
|
-
let i = {
|
|
363
|
-
hash: input.hash,
|
|
364
|
-
index: Number(input.index),
|
|
365
|
-
witnessUtxo: input.witnessUtxo,
|
|
366
|
-
nonWitnessUtxo: input.nonWitnessUtxo,
|
|
367
|
-
tapInternalKey: input.tapInternalKey,
|
|
368
|
-
sequence,
|
|
369
|
-
bip32Derivation: input.bip32Derivation,
|
|
370
|
-
};
|
|
371
|
-
if (!i.bip32Derivation)
|
|
372
|
-
delete i.bip32Derivation;
|
|
373
|
-
if (!i.nonWitnessUtxo)
|
|
374
|
-
delete i.nonWitnessUtxo;
|
|
375
|
-
newPsbt.addInput(i);
|
|
376
|
-
break;
|
|
377
|
-
}
|
|
378
|
-
default:
|
|
379
|
-
throw new Error("address type is incorrect");
|
|
380
|
-
}
|
|
418
|
+
const i = {
|
|
419
|
+
hash: input.hash,
|
|
420
|
+
index: +input.index,
|
|
421
|
+
witnessUtxo: input.witnessUtxo,
|
|
422
|
+
nonWitnessUtxo: input.nonWitnessUtxo,
|
|
423
|
+
redeemScript: input.redeemScript,
|
|
424
|
+
sequence,
|
|
425
|
+
bip32Derivation: input.bip32Derivation,
|
|
426
|
+
witnessScript: input.witnessScript,
|
|
427
|
+
tapInternalKey: input.tapInternalKey,
|
|
428
|
+
};
|
|
429
|
+
if (!i.bip32Derivation)
|
|
430
|
+
delete i.bip32Derivation;
|
|
431
|
+
if (!i.nonWitnessUtxo)
|
|
432
|
+
delete i.nonWitnessUtxo;
|
|
433
|
+
if (!i.witnessUtxo)
|
|
434
|
+
delete i.witnessUtxo;
|
|
435
|
+
if (!i.redeemScript)
|
|
436
|
+
delete i.redeemScript;
|
|
437
|
+
if (!i.witnessScript)
|
|
438
|
+
delete i.witnessScript;
|
|
439
|
+
if (!i.tapInternalKey)
|
|
440
|
+
delete i.tapInternalKey;
|
|
441
|
+
newPsbt.addInput(i);
|
|
381
442
|
}
|
|
382
443
|
for (const target of outputs) {
|
|
383
|
-
|
|
444
|
+
if (target.address) {
|
|
445
|
+
newPsbt.addOutput({ address: target.address, value: target.value });
|
|
446
|
+
}
|
|
447
|
+
else if (target.script) {
|
|
448
|
+
newPsbt.addOutput({ script: target.script, value: target.value });
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
throw new Error("invalid target");
|
|
452
|
+
}
|
|
384
453
|
}
|
|
385
|
-
if (change
|
|
454
|
+
if (change) {
|
|
386
455
|
newPsbt.addOutput(change);
|
|
387
456
|
}
|
|
388
|
-
if (change
|
|
457
|
+
if (change) {
|
|
389
458
|
if (newPsbt.txOutputs[outputs.length].address !== change.address) {
|
|
390
459
|
throw new Error("error change address");
|
|
391
460
|
}
|
|
461
|
+
if (newPsbt.txOutputs[outputs.length].value !== change.value) {
|
|
462
|
+
throw new Error("error change value");
|
|
463
|
+
}
|
|
392
464
|
}
|
|
393
465
|
const unsignedPsbtBaseText = newPsbt.toBase64();
|
|
394
|
-
const safeAddressTypeForPossibleTxId = ["p2wpkh", "p2tr"];
|
|
466
|
+
const safeAddressTypeForPossibleTxId = ["p2wpkh", "p2tr", "p2wsh"];
|
|
395
467
|
const isPossibleTxId = inputs.reduce((a, b) => a && safeAddressTypeForPossibleTxId.includes(b.signerInfo.addressType), true);
|
|
396
468
|
return {
|
|
397
469
|
unsignedTransaction: unsignedPsbtBaseText,
|
|
@@ -403,36 +475,47 @@ class BaseTransactionBuilder {
|
|
|
403
475
|
signerInfo: utx.signerInfo,
|
|
404
476
|
})),
|
|
405
477
|
fee,
|
|
478
|
+
feeRate,
|
|
406
479
|
change,
|
|
407
480
|
possibleTxId: isPossibleTxId ? this.getUnsignedPsbtTxId(unsignedPsbtBaseText) : undefined,
|
|
408
481
|
};
|
|
409
482
|
}
|
|
410
|
-
processUnsignedTransaction({ extendedUtxo, targets = [], changeAddress = undefined, fullAmount = false, feeRate, selectType = "normal", sequenceNumber, }) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
483
|
+
async processUnsignedTransaction({ extendedUtxo, targets = [], changeAddress = undefined, fullAmount = false, feeRate, selectType = "normal", sequenceNumber, requiredUtxo, }) {
|
|
484
|
+
let changeObject;
|
|
485
|
+
if (selectType === "full") {
|
|
486
|
+
if (targets.length !== 1 || !targets[0].address)
|
|
487
|
+
throw new Error("invalid targets");
|
|
488
|
+
changeObject = {
|
|
489
|
+
address: targets[0].address,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
if (!changeAddress)
|
|
494
|
+
throw new Error("no change address");
|
|
495
|
+
changeObject =
|
|
496
|
+
typeof changeAddress === "string"
|
|
497
|
+
? {
|
|
498
|
+
address: changeAddress,
|
|
499
|
+
}
|
|
500
|
+
: changeAddress;
|
|
501
|
+
}
|
|
502
|
+
const { inputs, outputs, change, fee } = await this.filterAndConvertTxDataToStandardFormat({
|
|
503
|
+
requiredUtxo,
|
|
504
|
+
extendedUtxo,
|
|
505
|
+
targets,
|
|
506
|
+
changeObject,
|
|
507
|
+
feeRate,
|
|
508
|
+
selectType: fullAmount ? "full" : selectType,
|
|
509
|
+
});
|
|
510
|
+
let unsignedTransaction = this.createUnsignedTransaction({
|
|
511
|
+
inputs,
|
|
512
|
+
outputs,
|
|
513
|
+
change,
|
|
514
|
+
fee,
|
|
515
|
+
feeRate,
|
|
516
|
+
sequenceNumber,
|
|
435
517
|
});
|
|
518
|
+
return unsignedTransaction;
|
|
436
519
|
}
|
|
437
520
|
getUnsignedPsbtTxId(unsignedPsbt) {
|
|
438
521
|
let psbt = bitcoin.Psbt.fromBase64(unsignedPsbt, {
|
|
@@ -440,6 +523,9 @@ class BaseTransactionBuilder {
|
|
|
440
523
|
});
|
|
441
524
|
return psbt.__CACHE.__TX.getId();
|
|
442
525
|
}
|
|
526
|
+
getTxFromHex(hex) {
|
|
527
|
+
return bitcoin.Transaction.fromHex(hex);
|
|
528
|
+
}
|
|
443
529
|
}
|
|
444
530
|
exports.BaseTransactionBuilder = BaseTransactionBuilder;
|
|
445
531
|
//# sourceMappingURL=transaction-builder.js.map
|