@teleportdao/bitcoin 3.0.3 → 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.
Files changed (105) hide show
  1. package/dist/bitcoin-interface-ordinal.d.ts +24 -24
  2. package/dist/bitcoin-interface-ordinal.d.ts.map +1 -1
  3. package/dist/bitcoin-interface-ordinal.js +89 -107
  4. package/dist/bitcoin-interface-ordinal.js.map +1 -1
  5. package/dist/bitcoin-interface-teleswap.d.ts +2 -2
  6. package/dist/bitcoin-interface-teleswap.d.ts.map +1 -1
  7. package/dist/bitcoin-interface-teleswap.js +77 -88
  8. package/dist/bitcoin-interface-teleswap.js.map +1 -1
  9. package/dist/bitcoin-interface-utils.d.ts +7 -4
  10. package/dist/bitcoin-interface-utils.d.ts.map +1 -1
  11. package/dist/bitcoin-interface-utils.js +11 -5
  12. package/dist/bitcoin-interface-utils.js.map +1 -1
  13. package/dist/bitcoin-interface-wallet.d.ts +1 -0
  14. package/dist/bitcoin-interface-wallet.d.ts.map +1 -1
  15. package/dist/bitcoin-interface-wallet.js +87 -95
  16. package/dist/bitcoin-interface-wallet.js.map +1 -1
  17. package/dist/bitcoin-interface.d.ts.map +1 -1
  18. package/dist/bitcoin-interface.js +58 -87
  19. package/dist/bitcoin-interface.js.map +1 -1
  20. package/dist/bitcoin-utils.d.ts +7 -4
  21. package/dist/bitcoin-utils.d.ts.map +1 -1
  22. package/dist/bitcoin-utils.js +93 -54
  23. package/dist/bitcoin-utils.js.map +1 -1
  24. package/dist/bitcoin-wallet-base.d.ts +23 -11
  25. package/dist/bitcoin-wallet-base.d.ts.map +1 -1
  26. package/dist/bitcoin-wallet-base.js +148 -138
  27. package/dist/bitcoin-wallet-base.js.map +1 -1
  28. package/dist/helper/brc20-helper.d.ts.map +1 -1
  29. package/dist/helper/brc20-helper.js +4 -6
  30. package/dist/helper/brc20-helper.js.map +1 -1
  31. package/dist/helper/index.js +17 -7
  32. package/dist/helper/index.js.map +1 -1
  33. package/dist/helper/ordinal-helper.d.ts +3 -9
  34. package/dist/helper/ordinal-helper.d.ts.map +1 -1
  35. package/dist/helper/ordinal-helper.js +20 -85
  36. package/dist/helper/ordinal-helper.js.map +1 -1
  37. package/dist/helper/teleswap-helper.d.ts.map +1 -1
  38. package/dist/helper/teleswap-helper.js +13 -12
  39. package/dist/helper/teleswap-helper.js.map +1 -1
  40. package/dist/index.d.ts +1 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +18 -7
  43. package/dist/index.js.map +1 -1
  44. package/dist/multisig-wallet-helper.d.ts +14 -1
  45. package/dist/multisig-wallet-helper.d.ts.map +1 -1
  46. package/dist/multisig-wallet-helper.js +135 -149
  47. package/dist/multisig-wallet-helper.js.map +1 -1
  48. package/dist/ordinal-wallet.d.ts +27 -19
  49. package/dist/ordinal-wallet.d.ts.map +1 -1
  50. package/dist/ordinal-wallet.js +263 -293
  51. package/dist/ordinal-wallet.js.map +1 -1
  52. package/dist/sign/sign-transaction.d.ts +5 -2
  53. package/dist/sign/sign-transaction.d.ts.map +1 -1
  54. package/dist/sign/sign-transaction.js +32 -39
  55. package/dist/sign/sign-transaction.js.map +1 -1
  56. package/dist/teleswap-wallet.d.ts +1 -0
  57. package/dist/teleswap-wallet.d.ts.map +1 -1
  58. package/dist/teleswap-wallet.js +40 -53
  59. package/dist/teleswap-wallet.js.map +1 -1
  60. package/dist/transaction-builder/bitcoin-transaction-builder.js +21 -21
  61. package/dist/transaction-builder/bitcoin-transaction-builder.js.map +1 -1
  62. package/dist/transaction-builder/coin-select.d.ts +19 -3
  63. package/dist/transaction-builder/coin-select.d.ts.map +1 -1
  64. package/dist/transaction-builder/coin-select.js +193 -181
  65. package/dist/transaction-builder/coin-select.js.map +1 -1
  66. package/dist/transaction-builder/index.d.ts +1 -0
  67. package/dist/transaction-builder/index.d.ts.map +1 -1
  68. package/dist/transaction-builder/index.js +1 -0
  69. package/dist/transaction-builder/index.js.map +1 -1
  70. package/dist/transaction-builder/ordinal-transaction-builder.d.ts +4 -4
  71. package/dist/transaction-builder/ordinal-transaction-builder.d.ts.map +1 -1
  72. package/dist/transaction-builder/ordinal-transaction-builder.js +51 -48
  73. package/dist/transaction-builder/ordinal-transaction-builder.js.map +1 -1
  74. package/dist/transaction-builder/transaction-builder.d.ts +57 -54
  75. package/dist/transaction-builder/transaction-builder.d.ts.map +1 -1
  76. package/dist/transaction-builder/transaction-builder.js +394 -308
  77. package/dist/transaction-builder/transaction-builder.js.map +1 -1
  78. package/dist/utils/networks.js +17 -7
  79. package/dist/utils/networks.js.map +1 -1
  80. package/dist/utils/tools.js +24 -35
  81. package/dist/utils/tools.js.map +1 -1
  82. package/package.json +4 -4
  83. package/src/bitcoin-interface-utils.ts +17 -8
  84. package/src/bitcoin-interface-wallet.ts +15 -1
  85. package/src/bitcoin-utils.ts +52 -3
  86. package/src/bitcoin-wallet-base.ts +67 -23
  87. package/src/helper/ordinal-helper.ts +0 -83
  88. package/src/index.ts +2 -0
  89. package/src/multisig-wallet-helper.ts +296 -0
  90. package/src/sign/sign-transaction.ts +5 -7
  91. package/src/transaction-builder/coin-select.ts +633 -0
  92. package/src/transaction-builder/index.ts +1 -0
  93. package/src/transaction-builder/transaction-builder.ts +424 -279
  94. package/dist/bitcoin-wallet-base copy.d.ts +0 -122
  95. package/dist/bitcoin-wallet-base copy.d.ts.map +0 -1
  96. package/dist/bitcoin-wallet-base copy.js +0 -279
  97. package/dist/bitcoin-wallet-base copy.js.map +0 -1
  98. package/dist/multisig-coordinator-wallet.d.ts +0 -2
  99. package/dist/multisig-coordinator-wallet.d.ts.map +0 -1
  100. package/dist/multisig-coordinator-wallet.js +0 -6
  101. package/dist/multisig-coordinator-wallet.js.map +0 -1
  102. package/dist/multisig-wallet.d.ts +0 -20
  103. package/dist/multisig-wallet.d.ts.map +0 -1
  104. package/dist/multisig-wallet.js +0 -119
  105. 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 (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
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 = exports.DUST = exports.componentBytes = void 0;
36
+ exports.BaseTransactionBuilder = void 0;
36
37
  const bitcoin = __importStar(require("bitcoinjs-lib"));
37
38
  const bitcoin_utils_1 = require("../bitcoin-utils");
38
- const coinselect = require("coinselect");
39
- const coinselectSplit = require("coinselect/split");
40
- const coinselectAccumulative = require("coinselect/accumulative");
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 * exports.componentBytes.bytePerInput.p2pkh;
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
- const inputsSizes = inputTypes.map((addressType) => exports.componentBytes.bytePerInput[addressType]);
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
- helperHandleInputsAndOutputs({ targets, extendedUtxo, feeRate, changeObject, selectType = "normal", }) {
128
- const filteredUtxo = extendedUtxo.filter((u) => u.value >
129
- +feeRate *
130
- exports.componentBytes.bytePerInput[u.signerInfo.addressType]);
131
- let selectResponse;
132
- switch (selectType) {
133
- case "normal":
134
- selectResponse = coinselect(filteredUtxo, targets, Math.round(feeRate));
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) => i.signerInfo.addressType), outputs, changeAddressType) + exports.componentBytes.bytePerOutput.default;
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 (Math.round(feeRate) === 1) {
167
- txFee = Math.round(txFee + txFee * 0.1);
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
- 0) {
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
- let changeIndex = outputs.findIndex((x) => !(x === null || x === void 0 ? void 0 : x.address) && !x.script && (x.value || 0) > 0);
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 (changeIndex >= 0 || diff > exports.DUST) {
129
+ if (diff > 0) {
184
130
  if (changeIndex >= 0) {
185
- diff = diff + exports.componentBytes.bytePerOutput.default * Math.round(feeRate);
186
- }
187
- if (diff < 0) {
188
- diff = 0;
189
- }
190
- if (selectType === "full") {
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: changeIndex >= 0 ? outputs[changeIndex].value + diff : diff,
144
+ value: diff - extraChangeFee,
200
145
  };
201
- fee = fee - diff;
146
+ fee = fee - diff + extraChangeFee;
202
147
  }
203
- if (changeIndex >= 0) {
204
- outputs.splice(changeIndex, 1);
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: outputs,
272
+ outputs,
211
273
  change,
212
274
  };
213
275
  }
214
- filterAndConvertTxDataToStandardFormat({ extendedUtxo, targets, changeObject, feeRate, selectType, }) {
215
- return __awaiter(this, void 0, void 0, function* () {
216
- let { inputs: filteredInputs, outputs, change, fee, } = this.helperHandleInputsAndOutputs({
217
- targets,
218
- extendedUtxo,
219
- feeRate,
220
- changeObject,
221
- selectType,
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
- var _a;
235
- return __awaiter(this, void 0, void 0, function* () {
236
- let inputs = baseInputs;
237
- const transactionHex = {};
238
- for (let i in inputs) {
239
- let { address, publicKey, derivationPath, masterFingerprint, addressType } = inputs[i].signerInfo;
240
- let addressObject = this.createAddressObject({
241
- publicKey: Buffer.from(publicKey, "hex"),
242
- addressType,
243
- });
244
- if (derivationPath && masterFingerprint && addressObject.pubkey) {
245
- inputs[i].bip32Derivation = [
246
- {
247
- path: derivationPath,
248
- pubkey: addressObject.pubkey,
249
- masterFingerprint: Buffer.from(masterFingerprint, "hex"),
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
- if (addressType === "p2pkh") {
254
- const txHex = transactionHex[inputs[i].hash] || (yield this._getTransactionHex(inputs[i].hash));
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
- else if (addressType === "p2wpkh") {
259
- if (!addressObject.output)
260
- throw new Error("invalid signer info");
261
- inputs[i].witnessUtxo = {
262
- script: addressObject.output,
263
- value: inputs[i].value,
264
- };
265
- if (inputs[i].signerInfo.includeHex) {
266
- const txHex = transactionHex[inputs[i].hash] || (yield this._getTransactionHex(inputs[i].hash));
267
- transactionHex[inputs[i].hash] = txHex;
268
- inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
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
- else if (addressType === "p2sh-p2wpkh") {
272
- if (!addressObject.output)
273
- throw new Error("invalid signer info");
274
- inputs[i].witnessUtxo = {
275
- script: addressObject.output,
276
- value: inputs[i].value,
277
- };
278
- if (!((_a = addressObject === null || addressObject === void 0 ? void 0 : addressObject.redeem) === null || _a === void 0 ? void 0 : _a.output))
279
- throw new Error("invalid signer info for p2sh address");
280
- inputs[i].redeemScript = addressObject.redeem.output;
281
- if (inputs[i].signerInfo.includeHex) {
282
- const txHex = transactionHex[inputs[i].hash] || (yield this._getTransactionHex(inputs[i].hash));
283
- transactionHex[inputs[i].hash] = txHex;
284
- inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
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
- else if (addressType === "p2tr") {
288
- if (!addressObject.output)
289
- throw new Error("invalid signer info");
290
- inputs[i].witnessUtxo = {
291
- script: addressObject.output,
292
- value: inputs[i].value,
293
- };
294
- if (!addressObject.pubkey)
295
- throw new Error("invalid signer info for p2tr address (pubkey)");
296
- inputs[i].tapInternalKey = addressObject.internalPubkey;
297
- if (inputs[i].signerInfo.includeHex) {
298
- const txHex = transactionHex[inputs[i].hash] || (yield this._getTransactionHex(inputs[i].hash));
299
- transactionHex[inputs[i].hash] = txHex;
300
- inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex");
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
- return inputs;
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
- let { addressType } = input.signerInfo;
314
- switch (addressType) {
315
- case "p2pkh": {
316
- let i = {
317
- hash: input.hash,
318
- index: Number(input.index),
319
- nonWitnessUtxo: input.nonWitnessUtxo,
320
- sequence,
321
- bip32Derivation: input.bip32Derivation,
322
- };
323
- if (!i.bip32Derivation)
324
- delete i.bip32Derivation;
325
- newPsbt.addInput(i);
326
- break;
327
- }
328
- case "p2wpkh": {
329
- let i = {
330
- hash: input.hash,
331
- index: Number(input.index),
332
- witnessUtxo: input.witnessUtxo,
333
- nonWitnessUtxo: input.nonWitnessUtxo,
334
- sequence,
335
- bip32Derivation: input.bip32Derivation,
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
- newPsbt.addOutput(target);
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 && Object.keys(change).length !== 0) {
454
+ if (change) {
386
455
  newPsbt.addOutput(change);
387
456
  }
388
- if (change && Object.keys(change).length !== 0) {
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
- return __awaiter(this, void 0, void 0, function* () {
412
- if (!changeAddress && targets.length === 0)
413
- throw new Error("no target");
414
- let changeObject = typeof changeAddress === "string"
415
- ? {
416
- address: changeAddress,
417
- }
418
- : changeAddress;
419
- const { inputs, outputs, change, fee } = yield this.filterAndConvertTxDataToStandardFormat({
420
- extendedUtxo,
421
- targets,
422
- changeObject,
423
- feeRate,
424
- selectType: fullAmount ? "full" : selectType,
425
- });
426
- let unsignedTransaction = this.createUnsignedTransaction({
427
- inputs,
428
- outputs,
429
- change,
430
- fee,
431
- feeRate,
432
- sequenceNumber,
433
- });
434
- return unsignedTransaction;
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