@btc-vision/transaction 1.0.85 → 1.0.86

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 (279) hide show
  1. package/.gitattributes +2 -2
  2. package/browser/_version.d.ts +1 -1
  3. package/browser/index.js +1 -1
  4. package/browser/keypair/Wallet.d.ts +3 -0
  5. package/browser/transaction/builders/TapUnwarpTransaction.d.ts +40 -40
  6. package/browser/transaction/builders/UnwarpTransaction.d.ts +34 -34
  7. package/browser/utxo/UTXOManager.d.ts +7 -7
  8. package/build/Utils.d.ts +0 -0
  9. package/build/Utils.js +1 -0
  10. package/build/_version.d.ts +1 -1
  11. package/build/_version.js +1 -1
  12. package/build/consensus/metadata/RoswsellConsensus.d.ts +2 -0
  13. package/build/consensus/metadata/RoswsellConsensus.js +4 -0
  14. package/build/contracts/ContractMetadataManager.d.ts +0 -0
  15. package/build/contracts/ContractMetadataManager.js +1 -0
  16. package/build/generators/OPNetAddressGenerator.d.ts +0 -0
  17. package/build/generators/OPNetAddressGenerator.js +1 -0
  18. package/build/generators/builders/UnwrapGenerator.d.ts +8 -0
  19. package/build/generators/builders/UnwrapGenerator.js +79 -0
  20. package/build/keypair/Wallet.d.ts +3 -0
  21. package/build/keypair/Wallet.js +8 -0
  22. package/build/keypair/interfaces/GeneratedWallet.d.ts +5 -0
  23. package/build/keypair/interfaces/GeneratedWallet.js +1 -0
  24. package/build/metadata/CommonContracts.d.ts +6 -0
  25. package/build/metadata/CommonContracts.js +5 -0
  26. package/build/metadata/ContractMetadataManager.d.ts +1 -0
  27. package/build/metadata/ContractMetadataManager.js +9 -0
  28. package/build/metadata/contracts/ContractBase.d.ts +9 -0
  29. package/build/metadata/contracts/ContractBase.js +13 -0
  30. package/build/metadata/contracts/ContractBaseMetadata.d.ts +9 -0
  31. package/build/metadata/contracts/ContractBaseMetadata.js +13 -0
  32. package/build/metadata/contracts/ContractMetadataManager.d.ts +0 -0
  33. package/build/metadata/contracts/ContractMetadataManager.js +1 -0
  34. package/build/network/NetworkConverter.d.ts +0 -0
  35. package/build/network/NetworkConverter.js +14 -0
  36. package/build/scripts/Regtest.d.ts +2 -0
  37. package/build/scripts/Regtest.js +15 -0
  38. package/build/scripts/test.d.ts +1 -0
  39. package/build/scripts/test.js +74 -0
  40. package/build/signer/Regtest.d.ts +2 -0
  41. package/build/signer/Regtest.js +15 -0
  42. package/build/tests/Regtest.d.ts +3 -0
  43. package/build/tests/Regtest.js +29 -0
  44. package/build/tests/adaptPSBT.d.ts +1 -0
  45. package/build/tests/adaptPSBT.js +44 -0
  46. package/build/tests/btc/send.d.ts +1 -0
  47. package/build/tests/btc/send.js +35 -0
  48. package/build/tests/btc/transfer.d.ts +1 -0
  49. package/build/tests/btc/transfer.js +35 -0
  50. package/build/tests/createPairReg.d.ts +1 -0
  51. package/build/tests/createPairReg.js +73 -0
  52. package/build/tests/deploy/deployMoto.d.ts +4 -0
  53. package/build/tests/deploy/deployMoto.js +89 -0
  54. package/build/tests/deploy/deployPool.d.ts +1 -0
  55. package/build/tests/deploy/deployPool.js +5 -0
  56. package/build/tests/deploy/deployStep1.d.ts +1 -0
  57. package/build/tests/deploy/deployStep1.js +5 -0
  58. package/build/tests/deploy/deployStep2.d.ts +1 -0
  59. package/build/tests/deploy/deployStep2.js +5 -0
  60. package/build/tests/deploy/deployStep3.d.ts +1 -0
  61. package/build/tests/deploy/deployStep3.js +5 -0
  62. package/build/tests/deploy.d.ts +1 -0
  63. package/build/tests/deploy.js +41 -0
  64. package/build/tests/deployMotoRegStep1.d.ts +1 -0
  65. package/build/tests/deployMotoRegStep1.js +85 -0
  66. package/build/tests/deployReg.d.ts +1 -0
  67. package/build/tests/deployReg.js +85 -0
  68. package/build/tests/factory/createPairReg.d.ts +1 -0
  69. package/build/tests/factory/createPairReg.js +13 -0
  70. package/build/tests/gen.d.ts +1 -0
  71. package/build/tests/gen.js +19 -0
  72. package/build/tests/interaction.d.ts +5 -0
  73. package/build/tests/interaction.js +62 -0
  74. package/build/tests/massWrapReg.d.ts +1 -0
  75. package/build/tests/massWrapReg.js +105 -0
  76. package/build/tests/mineReg.d.ts +1 -0
  77. package/build/tests/mineReg.js +19 -0
  78. package/build/tests/moto/airdropToken.d.ts +1 -0
  79. package/build/tests/moto/airdropToken.js +21 -0
  80. package/build/tests/moto/airdropTokens.d.ts +1 -0
  81. package/build/tests/moto/airdropTokens.js +60 -0
  82. package/build/tests/moto/allowance.d.ts +1 -0
  83. package/build/tests/moto/allowance.js +6 -0
  84. package/build/tests/moto/approve.d.ts +1 -0
  85. package/build/tests/moto/approve.js +10 -0
  86. package/build/tests/moto/approveWBTC.d.ts +1 -0
  87. package/build/tests/moto/approveWBTC.js +12 -0
  88. package/build/tests/moto/balanceOf.d.ts +1 -0
  89. package/build/tests/moto/balanceOf.js +12 -0
  90. package/build/tests/moto/transfer.d.ts +1 -0
  91. package/build/tests/moto/transfer.js +16 -0
  92. package/build/tests/motoswap/airdropToken.d.ts +11 -0
  93. package/build/tests/motoswap/airdropToken.js +36 -0
  94. package/build/tests/motoswap/deployMoto.d.ts +4 -0
  95. package/build/tests/motoswap/deployMoto.js +89 -0
  96. package/build/tests/motoswap/deployMotoRegStep1.d.ts +1 -0
  97. package/build/tests/motoswap/deployMotoRegStep1.js +91 -0
  98. package/build/tests/motoswap/deployMotoRegStep2.d.ts +1 -0
  99. package/build/tests/motoswap/deployMotoRegStep2.js +91 -0
  100. package/build/tests/motoswap/deployPool.d.ts +1 -0
  101. package/build/tests/motoswap/deployPool.js +5 -0
  102. package/build/tests/motoswap/deployStep1.d.ts +1 -0
  103. package/build/tests/motoswap/deployStep1.js +5 -0
  104. package/build/tests/motoswap/deployStep2.d.ts +1 -0
  105. package/build/tests/motoswap/deployStep2.js +5 -0
  106. package/build/tests/motoswap/deployStep3.d.ts +1 -0
  107. package/build/tests/motoswap/deployStep3.js +5 -0
  108. package/build/tests/motoswap/interaction.d.ts +3 -0
  109. package/build/tests/motoswap/interaction.js +63 -0
  110. package/build/tests/motoswap/routerAddLiquidity.d.ts +11 -0
  111. package/build/tests/motoswap/routerAddLiquidity.js +35 -0
  112. package/build/tests/motoswap-router/addLiquidity.d.ts +11 -0
  113. package/build/tests/motoswap-router/addLiquidity.js +36 -0
  114. package/build/tests/motoswap-router/deployMoto.d.ts +4 -0
  115. package/build/tests/motoswap-router/deployMoto.js +89 -0
  116. package/build/tests/motoswap-router/deployPool.d.ts +1 -0
  117. package/build/tests/motoswap-router/deployPool.js +5 -0
  118. package/build/tests/motoswap-router/deployStep1.d.ts +1 -0
  119. package/build/tests/motoswap-router/deployStep1.js +5 -0
  120. package/build/tests/motoswap-router/deployStep2.d.ts +1 -0
  121. package/build/tests/motoswap-router/deployStep2.js +5 -0
  122. package/build/tests/motoswap-router/deployStep3.d.ts +1 -0
  123. package/build/tests/motoswap-router/deployStep3.js +5 -0
  124. package/build/tests/motoswap-router/getAmountsOut.d.ts +5 -0
  125. package/build/tests/motoswap-router/getAmountsOut.js +34 -0
  126. package/build/tests/motoswap-router/routerAddLiquidity.d.ts +11 -0
  127. package/build/tests/motoswap-router/routerAddLiquidity.js +35 -0
  128. package/build/tests/motoswap-router/swap.d.ts +8 -0
  129. package/build/tests/motoswap-router/swap.js +24 -0
  130. package/build/tests/multisign.d.ts +1 -0
  131. package/build/tests/multisign.js +47 -0
  132. package/build/tests/multisign2.d.ts +1 -0
  133. package/build/tests/multisign2.js +27 -0
  134. package/build/tests/pool/DecodePoolAddress.d.ts +6 -0
  135. package/build/tests/pool/DecodePoolAddress.js +12 -0
  136. package/build/tests/pool/decodeReserves.d.ts +5 -0
  137. package/build/tests/pool/decodeReserves.js +13 -0
  138. package/build/tests/pool/reserves.d.ts +1 -0
  139. package/build/tests/pool/reserves.js +18 -0
  140. package/build/tests/shared/Utils.d.ts +2 -0
  141. package/build/tests/shared/Utils.js +14 -0
  142. package/build/tests/shared/interaction.d.ts +7 -0
  143. package/build/tests/shared/interaction.js +85 -0
  144. package/build/tests/shared/tokens.d.ts +6 -0
  145. package/build/tests/shared/tokens.js +5 -0
  146. package/build/tests/stakeReg.d.ts +1 -0
  147. package/build/tests/stakeReg.js +73 -0
  148. package/build/tests/stakedReg.d.ts +1 -0
  149. package/build/tests/stakedReg.js +28 -0
  150. package/build/tests/test.d.ts +1 -0
  151. package/build/tests/test.js +51 -0
  152. package/build/tests/test2.d.ts +1 -0
  153. package/build/tests/test2.js +73 -0
  154. package/build/tests/testReg.d.ts +1 -0
  155. package/build/tests/testReg.js +91 -0
  156. package/build/tests/tokens.d.ts +6 -0
  157. package/build/tests/tokens.js +5 -0
  158. package/build/tests/totalRewardReg.d.ts +1 -0
  159. package/build/tests/totalRewardReg.js +28 -0
  160. package/build/tests/transfer.d.ts +1 -0
  161. package/build/tests/transfer.js +74 -0
  162. package/build/tests/transferReg.d.ts +1 -0
  163. package/build/tests/transferReg.js +74 -0
  164. package/build/tests/unStakeReg.d.ts +1 -0
  165. package/build/tests/unStakeReg.js +72 -0
  166. package/build/tests/unwrapReg.d.ts +1 -0
  167. package/build/tests/unwrapReg.js +61 -0
  168. package/build/tests/unwrapReg2.d.ts +1 -0
  169. package/build/tests/unwrapReg2.js +56 -0
  170. package/build/tests/unwrapRegSegwit.d.ts +1 -0
  171. package/build/tests/unwrapRegSegwit.js +83 -0
  172. package/build/tests/wbtc/approve.d.ts +1 -0
  173. package/build/tests/wbtc/approve.js +6 -0
  174. package/build/tests/wbtc/approveWBTC.d.ts +1 -0
  175. package/build/tests/wbtc/approveWBTC.js +12 -0
  176. package/build/tests/wbtc/massWrapReg.d.ts +1 -0
  177. package/build/tests/wbtc/massWrapReg.js +105 -0
  178. package/build/tests/wbtc/transfer.d.ts +1 -0
  179. package/build/tests/wbtc/transfer.js +16 -0
  180. package/build/tests/wbtc/transferReg.d.ts +1 -0
  181. package/build/tests/wbtc/transferReg.js +16 -0
  182. package/build/tests/wbtc/unStakeReg.d.ts +1 -0
  183. package/build/tests/wbtc/unStakeReg.js +72 -0
  184. package/build/tests/wbtc/unwrapReg.d.ts +1 -0
  185. package/build/tests/wbtc/unwrapReg.js +60 -0
  186. package/build/tests/wbtc/unwrapRegSegwit.d.ts +1 -0
  187. package/build/tests/wbtc/unwrapRegSegwit.js +83 -0
  188. package/build/tests/wbtc/withdrawalRequestReg.d.ts +1 -0
  189. package/build/tests/wbtc/withdrawalRequestReg.js +71 -0
  190. package/build/tests/wbtc/wrapReg.d.ts +1 -0
  191. package/build/tests/wbtc/wrapReg.js +65 -0
  192. package/build/tests/wbtc/wrapTest.d.ts +1 -0
  193. package/build/tests/wbtc/wrapTest.js +66 -0
  194. package/build/tests/withdrawalRequestReg.d.ts +1 -0
  195. package/build/tests/withdrawalRequestReg.js +71 -0
  196. package/build/tests/wrap.d.ts +1 -0
  197. package/build/tests/wrap.js +65 -0
  198. package/build/tests/wrapReg.d.ts +1 -0
  199. package/build/tests/wrapReg.js +68 -0
  200. package/build/tests/wrapTest.d.ts +1 -0
  201. package/build/tests/wrapTest.js +66 -0
  202. package/build/tests/wrapTestg.d.ts +1 -0
  203. package/build/tests/wrapTestg.js +66 -0
  204. package/build/tests/writers/allowance.d.ts +3 -0
  205. package/build/tests/writers/allowance.js +10 -0
  206. package/build/tests/writers/approve.d.ts +4 -0
  207. package/build/tests/writers/approve.js +11 -0
  208. package/build/transaction/TransactionBuilder.d.ts +60 -0
  209. package/build/transaction/TransactionBuilder.js +244 -0
  210. package/build/transaction/browser/BrowserSigner.d.ts +11 -0
  211. package/build/transaction/browser/BrowserSigner.js +10 -0
  212. package/build/transaction/browser/extensions/Unisat.d.ts +54 -0
  213. package/build/transaction/browser/extensions/Unisat.js +11 -0
  214. package/build/transaction/builders/GenericTransaction.d.ts +11 -0
  215. package/build/transaction/builders/GenericTransaction.js +23 -0
  216. package/build/transaction/builders/TapUnwarpTransaction.d.ts +37 -0
  217. package/build/transaction/builders/TapUnwarpTransaction.js +201 -0
  218. package/build/transaction/builders/UnwarpSegwitTransaction.d.ts +34 -0
  219. package/build/transaction/builders/UnwarpSegwitTransaction.js +184 -0
  220. package/build/transaction/builders/UnwarpTransaction.d.ts +35 -0
  221. package/build/transaction/builders/UnwarpTransaction.js +199 -0
  222. package/build/transaction/interfaces/ITransactions.d.ts +32 -0
  223. package/build/transaction/interfaces/ITransactions.js +1 -0
  224. package/build/utxo/IUTXO.d.ts +0 -0
  225. package/build/utxo/IUTXO.js +1 -0
  226. package/build/utxo/OPNetUtils.d.ts +7 -0
  227. package/build/utxo/OPNetUtils.js +47 -0
  228. package/build/utxo/UTXOManager.d.ts +7 -0
  229. package/build/utxo/UTXOManager.js +47 -0
  230. package/build/wbtc/BroadcastResponse.d.ts +0 -0
  231. package/build/wbtc/BroadcastResponse.js +1 -0
  232. package/gulpfile.js +152 -152
  233. package/package.json +109 -109
  234. package/src/_version.ts +1 -1
  235. package/src/consensus/Consensus.ts +36 -36
  236. package/src/consensus/ConsensusConfig.ts +39 -39
  237. package/src/crypto/crypto-browser.js +75 -75
  238. package/src/generators/AddressGenerator.ts +24 -24
  239. package/src/generators/Features.ts +5 -5
  240. package/src/generators/Generator.ts +75 -75
  241. package/src/generators/builders/CalldataGenerator.ts +148 -148
  242. package/src/generators/builders/DeploymentGenerator.ts +66 -66
  243. package/src/index.ts +4 -4
  244. package/src/keypair/AddressVerificator.ts +40 -40
  245. package/src/keypair/EcKeyPair.ts +282 -282
  246. package/src/keypair/Wallet.ts +120 -97
  247. package/src/keypair/interfaces/IWallet.ts +19 -19
  248. package/src/metadata/ContractBaseMetadata.ts +23 -23
  249. package/src/metadata/contracts/wBTC.ts +60 -60
  250. package/src/metadata/tokens.ts +135 -135
  251. package/src/network/NetworkInformation.ts +7 -7
  252. package/src/transaction/TransactionFactory.ts +496 -496
  253. package/src/transaction/browser/BrowserSignerBase.ts +37 -37
  254. package/src/transaction/browser/Web3Provider.ts +46 -46
  255. package/src/transaction/browser/extensions/UnisatSigner.ts +218 -218
  256. package/src/transaction/browser/types/Unisat.ts +97 -97
  257. package/src/transaction/builders/FundingTransaction.ts +40 -40
  258. package/src/transaction/builders/InteractionTransaction.ts +38 -38
  259. package/src/transaction/builders/SharedInteractionTransaction.ts +368 -368
  260. package/src/transaction/builders/TransactionBuilder.ts +665 -665
  261. package/src/transaction/builders/UnwrapSegwitTransaction.ts +365 -365
  262. package/src/transaction/builders/UnwrapTransaction.ts +507 -507
  263. package/src/transaction/builders/WrapTransaction.ts +346 -346
  264. package/src/transaction/interfaces/ITransactionParameters.ts +59 -59
  265. package/src/transaction/interfaces/Tap.ts +26 -26
  266. package/src/transaction/psbt/PSBTTypes.ts +3 -3
  267. package/src/transaction/shared/TweakedTransaction.ts +539 -539
  268. package/src/utxo/OPNetLimitedProvider.ts +244 -244
  269. package/src/utxo/interfaces/BroadcastResponse.ts +10 -10
  270. package/src/utxo/interfaces/IUTXO.ts +29 -29
  271. package/src/verification/TapscriptVerificator.ts +89 -89
  272. package/src/wbtc/Generate.ts +40 -40
  273. package/src/wbtc/UnwrapGeneration.ts +13 -13
  274. package/src/wbtc/WrappedGenerationParameters.ts +33 -33
  275. package/webpack.config.js +78 -78
  276. /package/build/generators/builders/{MultiSignGenerator.d.ts → MultisignGenerator.d.ts} +0 -0
  277. /package/build/generators/builders/{MultiSignGenerator.js → MultisignGenerator.js} +0 -0
  278. /package/build/generators/{Features.d.ts → features.d.ts} +0 -0
  279. /package/build/generators/{Features.js → features.js} +0 -0
@@ -1,665 +1,665 @@
1
- import { initEccLib, Network, opcodes, Psbt, script, Signer, Transaction } from 'bitcoinjs-lib';
2
- import { varuint } from 'bitcoinjs-lib/src/bufferutils.js';
3
- import * as ecc from '@bitcoinerlab/secp256k1';
4
- import { PsbtInputExtended, PsbtOutputExtended, UpdateInput } from '../interfaces/Tap.js';
5
- import { TransactionType } from '../enums/TransactionType.js';
6
- import {
7
- IFundingTransactionParameters,
8
- ITransactionParameters,
9
- } from '../interfaces/ITransactionParameters.js';
10
- import { EcKeyPair } from '../../keypair/EcKeyPair.js';
11
- import { Address } from '@btc-vision/bsi-binary';
12
- import { UTXO } from '../../utxo/interfaces/IUTXO.js';
13
- import { ECPairInterface } from 'ecpair';
14
- import { AddressVerificator } from '../../keypair/AddressVerificator.js';
15
- import { TweakedTransaction } from '../shared/TweakedTransaction.js';
16
-
17
- initEccLib(ecc);
18
-
19
- /**
20
- * Allows to build a transaction like you would on Ethereum.
21
- * @description The transaction builder class
22
- * @abstract
23
- * @class TransactionBuilder
24
- */
25
- export abstract class TransactionBuilder<T extends TransactionType> extends TweakedTransaction {
26
- public static readonly LOCK_LEAF_SCRIPT: Buffer = script.compile([
27
- opcodes.OP_0,
28
- //opcodes.OP_VERIFY, - verify that this is not needed.
29
- ]);
30
-
31
- public static readonly MINIMUM_DUST: bigint = 330n;
32
-
33
- public abstract readonly type: T;
34
- public readonly logColor: string = '#785def';
35
-
36
- /**
37
- * @description The overflow fees of the transaction
38
- * @public
39
- */
40
- public overflowFees: bigint = 0n;
41
-
42
- /**
43
- * @description Cost in satoshis of the transaction fee
44
- */
45
- public transactionFee: bigint = 0n;
46
- /**
47
- * @description The estimated fees of the transaction
48
- */
49
- public estimatedFees: bigint = 0n;
50
- /**
51
- * @description The transaction itself.
52
- */
53
- protected transaction: Psbt;
54
- /**
55
- * @description Inputs to update later on.
56
- */
57
- protected readonly updateInputs: UpdateInput[] = [];
58
- /**
59
- * @description The outputs of the transaction
60
- */
61
- protected readonly outputs: PsbtOutputExtended[] = [];
62
- /**
63
- * @description Output that will be used to pay the fees
64
- */
65
- protected feeOutput: PsbtOutputExtended | null = null;
66
- /**
67
- * @description The total amount of satoshis in the inputs
68
- */
69
- protected totalInputAmount: bigint;
70
- /**
71
- * @description The signer of the transaction
72
- */
73
- protected readonly signer: Signer;
74
- /**
75
- * @description The network where the transaction will be broadcasted
76
- */
77
- protected readonly network: Network;
78
- /**
79
- * @description The fee rate of the transaction
80
- */
81
- protected readonly feeRate: number;
82
- /**
83
- * @description The opnet priority fee of the transaction
84
- */
85
- protected priorityFee: bigint;
86
- /**
87
- * @description The utxos used in the transaction
88
- */
89
- protected utxos: UTXO[];
90
- /**
91
- * @description The address where the transaction is sent to
92
- * @protected
93
- */
94
- protected to: Address | undefined;
95
- /**
96
- * @description The address where the transaction is sent from
97
- * @protected
98
- */
99
- protected from: Address;
100
- /**
101
- * @description The maximum fee rate of the transaction
102
- */
103
- protected _maximumFeeRate: number = 100000000;
104
-
105
- /**
106
- * @param {ITransactionParameters} parameters - The transaction parameters
107
- */
108
- protected constructor(parameters: ITransactionParameters) {
109
- super(parameters);
110
-
111
- if (parameters.estimatedFees) {
112
- this.estimatedFees = parameters.estimatedFees;
113
- }
114
-
115
- this.signer = parameters.signer;
116
- this.network = parameters.network;
117
- this.feeRate = parameters.feeRate;
118
- this.priorityFee = parameters.priorityFee;
119
- this.utxos = parameters.utxos;
120
- this.to = parameters.to || undefined;
121
-
122
- this.from = TransactionBuilder.getFrom(
123
- parameters.from,
124
- this.signer as ECPairInterface,
125
- this.network,
126
- );
127
-
128
- this.totalInputAmount = this.calculateTotalUTXOAmount();
129
-
130
- const totalVOut: bigint = this.calculateTotalVOutAmount();
131
- if (totalVOut < this.totalInputAmount) {
132
- throw new Error(`Vout value is less than the value to send`);
133
- }
134
-
135
- this.transaction = new Psbt({
136
- network: this.network,
137
- });
138
- }
139
-
140
- public static getFrom(
141
- from: string | undefined,
142
- keypair: ECPairInterface,
143
- network: Network,
144
- ): Address {
145
- return from || EcKeyPair.getTaprootAddress(keypair, network);
146
- }
147
-
148
- /**
149
- * @description Converts the witness stack to a script witness
150
- * @param {Buffer[]} witness - The witness stack
151
- * @protected
152
- * @returns {Buffer}
153
- */
154
- public static witnessStackToScriptWitness(witness: Buffer[]): Buffer {
155
- let buffer = Buffer.allocUnsafe(0);
156
-
157
- function writeSlice(slice: Buffer) {
158
- buffer = Buffer.concat([buffer, Buffer.from(slice)]);
159
- }
160
-
161
- function writeVarInt(i: number) {
162
- const currentLen = buffer.length;
163
- const varintLen = varuint.encodingLength(i);
164
-
165
- buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
166
- varuint.encode(i, buffer, currentLen);
167
- }
168
-
169
- function writeVarSlice(slice: Buffer) {
170
- writeVarInt(slice.length);
171
- writeSlice(slice);
172
- }
173
-
174
- function writeVector(vector: Buffer[]) {
175
- writeVarInt(vector.length);
176
- vector.forEach(writeVarSlice);
177
- }
178
-
179
- writeVector(witness);
180
-
181
- return buffer;
182
- }
183
-
184
- public async getFundingTransactionParameters(): Promise<IFundingTransactionParameters> {
185
- if (!this.estimatedFees) {
186
- this.estimatedFees = await this.estimateTransactionFees();
187
- }
188
-
189
- return {
190
- utxos: this.utxos,
191
- to: this.getScriptAddress(),
192
- signer: this.signer,
193
- network: this.network,
194
- feeRate: this.feeRate,
195
- priorityFee: this.priorityFee,
196
- from: this.from,
197
- amount: this.estimatedFees,
198
- };
199
- }
200
-
201
- /**
202
- * Set the destination address of the transaction
203
- * @param {Address} address - The address to set
204
- */
205
- public setDestinationAddress(address: Address): void {
206
- this.to = address; // this.getScriptAddress()
207
- }
208
-
209
- /**
210
- * Set the maximum fee rate of the transaction in satoshis per byte
211
- * @param {number} feeRate - The fee rate to set
212
- * @public
213
- */
214
- public setMaximumFeeRate(feeRate: number): void {
215
- this._maximumFeeRate = feeRate;
216
- }
217
-
218
- /**
219
- * @description Signs the transaction
220
- * @public
221
- * @returns {Promise<Transaction>} - The signed transaction in hex format
222
- * @throws {Error} - If something went wrong
223
- */
224
- public async signTransaction(): Promise<Transaction> {
225
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
226
- throw new Error(
227
- 'Invalid contract address. The contract address must be a taproot address.',
228
- );
229
- }
230
-
231
- if (this.signed) throw new Error('Transaction is already signed');
232
- this.signed = true;
233
-
234
- await this.buildTransaction();
235
-
236
- const builtTx = await this.internalBuildTransaction(this.transaction);
237
- if (builtTx) {
238
- if (this.regenerated) {
239
- throw new Error('Transaction was regenerated');
240
- }
241
-
242
- return this.transaction.extractTransaction(false);
243
- }
244
-
245
- throw new Error('Could not sign transaction');
246
- }
247
-
248
- /**
249
- * @description Generates the transaction minimal signatures
250
- * @public
251
- */
252
- public async generateTransactionMinimalSignatures(): Promise<void> {
253
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
254
- throw new Error(
255
- 'Invalid contract address. The contract address must be a taproot address.',
256
- );
257
- }
258
-
259
- await this.buildTransaction();
260
-
261
- if (this.transaction.data.inputs.length === 0) {
262
- const inputs: PsbtInputExtended[] = this.getInputs();
263
- const outputs: PsbtOutputExtended[] = this.getOutputs();
264
-
265
- this.transaction.setMaximumFeeRate(this._maximumFeeRate);
266
- this.transaction.addInputs(inputs);
267
-
268
- for (let i = 0; i < this.updateInputs.length; i++) {
269
- this.transaction.updateInput(i, this.updateInputs[i]);
270
- }
271
-
272
- this.transaction.addOutputs(outputs);
273
- }
274
- }
275
-
276
- /**
277
- * @description Signs the transaction
278
- * @public
279
- * @returns {Promise<Psbt>} - The signed transaction in hex format
280
- * @throws {Error} - If something went wrong
281
- */
282
- public async signPSBT(): Promise<Psbt> {
283
- if (await this.signTransaction()) {
284
- return this.transaction;
285
- }
286
-
287
- throw new Error('Could not sign transaction');
288
- }
289
-
290
- /**
291
- * Add an input to the transaction.
292
- * @param {PsbtInputExtended} input - The input to add
293
- * @public
294
- * @returns {void}
295
- */
296
- public addInput(input: PsbtInputExtended): void {
297
- this.inputs.push(input);
298
- }
299
-
300
- /**
301
- * Add an output to the transaction.
302
- * @param {PsbtOutputExtended} output - The output to add
303
- * @public
304
- * @returns {void}
305
- */
306
- public addOutput(output: PsbtOutputExtended): void {
307
- if (output.value === 0) return;
308
- if (output.value < TransactionBuilder.MINIMUM_DUST) {
309
- throw new Error(
310
- `Output value is less than the minimum dust ${output.value} < ${TransactionBuilder.MINIMUM_DUST}`,
311
- );
312
- }
313
-
314
- this.outputs.push(output);
315
- }
316
-
317
- /**
318
- * Receiver address.
319
- * @public
320
- * @returns {Address} - The receiver address
321
- */
322
- public toAddress(): string | undefined {
323
- return this.to;
324
- }
325
-
326
- /**
327
- * @description Returns the script address
328
- * @returns {Address} - The script address
329
- */
330
- public address(): Address | undefined {
331
- return this.tapData?.address;
332
- }
333
-
334
- /**
335
- * Estimates the transaction fees.
336
- * @public
337
- * @returns {Promise<bigint>} - The estimated transaction fees
338
- */
339
- public async estimateTransactionFees(): Promise<bigint> {
340
- if (this.estimatedFees) return this.estimatedFees;
341
-
342
- const fakeTx = new Psbt({
343
- network: this.network,
344
- });
345
-
346
- const builtTx = await this.internalBuildTransaction(fakeTx);
347
- if (builtTx) {
348
- const tx = fakeTx.extractTransaction(true, true);
349
- const size = tx.virtualSize();
350
- const fee: number = this.feeRate * size;
351
-
352
- this.estimatedFees = BigInt(Math.ceil(fee) + 1);
353
-
354
- return this.estimatedFees;
355
- } else {
356
- throw new Error(
357
- `Could not build transaction to estimate fee. Something went wrong while building the transaction.`,
358
- );
359
- }
360
- }
361
-
362
- public async rebuildFromBase64(base64: string): Promise<Psbt> {
363
- this.transaction = Psbt.fromBase64(base64, { network: this.network });
364
- this.signed = false;
365
-
366
- this.sighashTypes = [Transaction.SIGHASH_ANYONECANPAY, Transaction.SIGHASH_ALL];
367
-
368
- return await this.signPSBT();
369
- }
370
-
371
- public setPSBT(psbt: Psbt): void {
372
- this.transaction = psbt;
373
- }
374
-
375
- /**
376
- * @description Adds the refund output to the transaction
377
- * @param {bigint} amountSpent - The amount spent
378
- * @protected
379
- * @returns {Promise<void>}
380
- */
381
- protected async addRefundOutput(amountSpent: bigint): Promise<void> {
382
- /** Add the refund output */
383
- const sendBackAmount: bigint = this.totalInputAmount - amountSpent;
384
- if (sendBackAmount >= TransactionBuilder.MINIMUM_DUST) {
385
- if (AddressVerificator.isValidP2TRAddress(this.from, this.network)) {
386
- await this.setFeeOutput({
387
- value: Number(sendBackAmount),
388
- address: this.from,
389
- tapInternalKey: this.internalPubKeyToXOnly(),
390
- });
391
- } else {
392
- await this.setFeeOutput({
393
- value: Number(sendBackAmount),
394
- address: this.from,
395
- });
396
- }
397
-
398
- return;
399
- }
400
-
401
- this.warn(
402
- `Amount to send back (${sendBackAmount} sat) is less than the minimum dust (${TransactionBuilder.MINIMUM_DUST} sat), it will be consumed in fees instead.`,
403
- );
404
- }
405
-
406
- /**
407
- * @description Adds the value to the output
408
- * @param {number | bigint} value - The value to add
409
- * @protected
410
- * @returns {void}
411
- */
412
- protected addValueToToOutput(value: number | bigint): void {
413
- if (value < TransactionBuilder.MINIMUM_DUST) {
414
- throw new Error(
415
- `Value to send is less than the minimum dust ${value} < ${TransactionBuilder.MINIMUM_DUST}`,
416
- );
417
- }
418
-
419
- for (let output of this.outputs) {
420
- if ('address' in output && output.address === this.to) {
421
- output.value += Number(value);
422
- return;
423
- }
424
- }
425
-
426
- throw new Error('Output not found');
427
- }
428
-
429
- /**
430
- * @description Returns the transaction opnet fee
431
- * @protected
432
- * @returns {bigint}
433
- */
434
- protected getTransactionOPNetFee(): bigint {
435
- if (this.priorityFee > TransactionBuilder.MINIMUM_DUST) {
436
- return this.priorityFee;
437
- }
438
-
439
- return TransactionBuilder.MINIMUM_DUST;
440
- }
441
-
442
- /**
443
- * @description Returns the total amount of satoshis in the inputs
444
- * @protected
445
- * @returns {bigint}
446
- */
447
- protected calculateTotalUTXOAmount(): bigint {
448
- let total: bigint = 0n;
449
- for (let utxo of this.utxos) {
450
- total += utxo.value;
451
- }
452
-
453
- return total;
454
- }
455
-
456
- /**
457
- * @description Returns the total amount of satoshis in the outputs
458
- * @protected
459
- * @returns {bigint}
460
- */
461
- protected calculateTotalVOutAmount(): bigint {
462
- let total: bigint = 0n;
463
- for (let utxo of this.utxos) {
464
- total += utxo.value;
465
- }
466
-
467
- return total;
468
- }
469
-
470
- /**
471
- * @description Adds the inputs from the utxos
472
- * @protected
473
- * @returns {void}
474
- */
475
- protected addInputsFromUTXO(): void {
476
- if (this.utxos.length) {
477
- //throw new Error('No UTXOs specified');
478
-
479
- if (this.totalInputAmount < TransactionBuilder.MINIMUM_DUST) {
480
- throw new Error(
481
- `Total input amount is ${this.totalInputAmount} sat which is less than the minimum dust ${TransactionBuilder.MINIMUM_DUST} sat.`,
482
- );
483
- }
484
-
485
- for (let i = 0; i < this.utxos.length; i++) {
486
- const utxo = this.utxos[i];
487
- const input = this.generatePsbtInputExtended(utxo, i);
488
-
489
- this.addInput(input);
490
- }
491
- }
492
- }
493
-
494
- /**
495
- * Internal init.
496
- * @protected
497
- */
498
- protected override internalInit(): void {
499
- this.verifyUTXOValidity();
500
-
501
- super.internalInit();
502
- }
503
-
504
- /**
505
- * Builds the transaction.
506
- * @protected
507
- * @returns {Promise<void>}
508
- */
509
- protected abstract buildTransaction(): Promise<void>;
510
-
511
- /**
512
- * Add an input update
513
- * @param {UpdateInput} input - The input to update
514
- * @protected
515
- * @returns {void}
516
- */
517
- protected updateInput(input: UpdateInput): void {
518
- this.updateInputs.push(input);
519
- }
520
-
521
- /**
522
- * Returns the witness of the tap transaction.
523
- * @protected
524
- * @returns {Buffer}
525
- */
526
- protected getWitness(): Buffer {
527
- if (!this.tapData || !this.tapData.witness) {
528
- throw new Error('Witness is required');
529
- }
530
-
531
- if (this.tapData.witness.length === 0) {
532
- throw new Error('Witness is empty');
533
- }
534
-
535
- return this.tapData.witness[this.tapData.witness.length - 1];
536
- }
537
-
538
- /**
539
- * Returns the tap output.
540
- * @protected
541
- * @returns {Buffer}
542
- */
543
- protected getTapOutput(): Buffer {
544
- if (!this.tapData || !this.tapData.output) {
545
- throw new Error('Tap data is required');
546
- }
547
-
548
- return this.tapData.output;
549
- }
550
-
551
- /**
552
- * Returns the inputs of the transaction.
553
- * @protected
554
- * @returns {PsbtInputExtended[]}
555
- */
556
- protected getInputs(): PsbtInputExtended[] {
557
- return this.inputs;
558
- }
559
-
560
- /**
561
- * Returns the outputs of the transaction.
562
- * @protected
563
- * @returns {PsbtOutputExtended[]}
564
- */
565
- protected getOutputs(): PsbtOutputExtended[] {
566
- const outputs: PsbtOutputExtended[] = [...this.outputs];
567
- if (this.feeOutput) outputs.push(this.feeOutput);
568
-
569
- return outputs;
570
- }
571
-
572
- /**
573
- * Verifies that the utxos are valid.
574
- * @protected
575
- */
576
- protected verifyUTXOValidity(): void {
577
- for (let utxo of this.utxos) {
578
- if (!utxo.scriptPubKey) {
579
- throw new Error('Address is required');
580
- }
581
- }
582
- }
583
-
584
- /**
585
- * Set transaction fee output.
586
- * @param {PsbtOutputExtended} output - The output to set the fees
587
- * @protected
588
- * @returns {Promise<void>}
589
- */
590
- protected async setFeeOutput(output: PsbtOutputExtended): Promise<void> {
591
- const initialValue = output.value;
592
-
593
- let fee = await this.estimateTransactionFees();
594
- output.value = initialValue - Number(fee);
595
-
596
- if (output.value < TransactionBuilder.MINIMUM_DUST) {
597
- this.feeOutput = null;
598
-
599
- if (output.value < 0) {
600
- throw new Error(
601
- `setFeeOutput: Insufficient funds to pay the fees. Fee: ${fee} > Value: ${initialValue}. Total input: ${this.totalInputAmount} sat`,
602
- );
603
- }
604
- } else {
605
- this.feeOutput = output;
606
-
607
- let fee = await this.estimateTransactionFees();
608
- if (fee > BigInt(initialValue)) {
609
- throw new Error(
610
- `estimateTransactionFees: Insufficient funds to pay the fees. Fee: ${fee} > Value: ${initialValue}. Total input: ${this.totalInputAmount} sat`,
611
- );
612
- }
613
-
614
- const valueLeft = initialValue - Number(fee);
615
- if (valueLeft < TransactionBuilder.MINIMUM_DUST) {
616
- this.feeOutput = null;
617
- } else {
618
- this.feeOutput.value = valueLeft;
619
- }
620
-
621
- this.overflowFees = BigInt(valueLeft);
622
- }
623
- }
624
-
625
- /**
626
- * Builds the transaction.
627
- * @param {Psbt} transaction - The transaction to build
628
- * @protected
629
- * @returns {Promise<boolean>}
630
- * @throws {Error} - If something went wrong while building the transaction
631
- */
632
- protected async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
633
- if (transaction.data.inputs.length === 0) {
634
- const inputs: PsbtInputExtended[] = this.getInputs();
635
- const outputs: PsbtOutputExtended[] = this.getOutputs();
636
-
637
- transaction.setMaximumFeeRate(this._maximumFeeRate);
638
- transaction.addInputs(inputs);
639
-
640
- for (let i = 0; i < this.updateInputs.length; i++) {
641
- transaction.updateInput(i, this.updateInputs[i]);
642
- }
643
-
644
- transaction.addOutputs(outputs);
645
- }
646
-
647
- try {
648
- await this.signInputs(transaction);
649
-
650
- if (this.finalized) {
651
- this.transactionFee = BigInt(transaction.getFee());
652
- }
653
-
654
- return true;
655
- } catch (e) {
656
- const err: Error = e as Error;
657
-
658
- this.error(
659
- `[internalBuildTransaction] Something went wrong while getting building the transaction: ${err.stack}`,
660
- );
661
- }
662
-
663
- return false;
664
- }
665
- }
1
+ import { initEccLib, Network, opcodes, Psbt, script, Signer, Transaction } from 'bitcoinjs-lib';
2
+ import { varuint } from 'bitcoinjs-lib/src/bufferutils.js';
3
+ import * as ecc from '@bitcoinerlab/secp256k1';
4
+ import { PsbtInputExtended, PsbtOutputExtended, UpdateInput } from '../interfaces/Tap.js';
5
+ import { TransactionType } from '../enums/TransactionType.js';
6
+ import {
7
+ IFundingTransactionParameters,
8
+ ITransactionParameters,
9
+ } from '../interfaces/ITransactionParameters.js';
10
+ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
11
+ import { Address } from '@btc-vision/bsi-binary';
12
+ import { UTXO } from '../../utxo/interfaces/IUTXO.js';
13
+ import { ECPairInterface } from 'ecpair';
14
+ import { AddressVerificator } from '../../keypair/AddressVerificator.js';
15
+ import { TweakedTransaction } from '../shared/TweakedTransaction.js';
16
+
17
+ initEccLib(ecc);
18
+
19
+ /**
20
+ * Allows to build a transaction like you would on Ethereum.
21
+ * @description The transaction builder class
22
+ * @abstract
23
+ * @class TransactionBuilder
24
+ */
25
+ export abstract class TransactionBuilder<T extends TransactionType> extends TweakedTransaction {
26
+ public static readonly LOCK_LEAF_SCRIPT: Buffer = script.compile([
27
+ opcodes.OP_0,
28
+ //opcodes.OP_VERIFY, - verify that this is not needed.
29
+ ]);
30
+
31
+ public static readonly MINIMUM_DUST: bigint = 330n;
32
+
33
+ public abstract readonly type: T;
34
+ public readonly logColor: string = '#785def';
35
+
36
+ /**
37
+ * @description The overflow fees of the transaction
38
+ * @public
39
+ */
40
+ public overflowFees: bigint = 0n;
41
+
42
+ /**
43
+ * @description Cost in satoshis of the transaction fee
44
+ */
45
+ public transactionFee: bigint = 0n;
46
+ /**
47
+ * @description The estimated fees of the transaction
48
+ */
49
+ public estimatedFees: bigint = 0n;
50
+ /**
51
+ * @description The transaction itself.
52
+ */
53
+ protected transaction: Psbt;
54
+ /**
55
+ * @description Inputs to update later on.
56
+ */
57
+ protected readonly updateInputs: UpdateInput[] = [];
58
+ /**
59
+ * @description The outputs of the transaction
60
+ */
61
+ protected readonly outputs: PsbtOutputExtended[] = [];
62
+ /**
63
+ * @description Output that will be used to pay the fees
64
+ */
65
+ protected feeOutput: PsbtOutputExtended | null = null;
66
+ /**
67
+ * @description The total amount of satoshis in the inputs
68
+ */
69
+ protected totalInputAmount: bigint;
70
+ /**
71
+ * @description The signer of the transaction
72
+ */
73
+ protected readonly signer: Signer;
74
+ /**
75
+ * @description The network where the transaction will be broadcasted
76
+ */
77
+ protected readonly network: Network;
78
+ /**
79
+ * @description The fee rate of the transaction
80
+ */
81
+ protected readonly feeRate: number;
82
+ /**
83
+ * @description The opnet priority fee of the transaction
84
+ */
85
+ protected priorityFee: bigint;
86
+ /**
87
+ * @description The utxos used in the transaction
88
+ */
89
+ protected utxos: UTXO[];
90
+ /**
91
+ * @description The address where the transaction is sent to
92
+ * @protected
93
+ */
94
+ protected to: Address | undefined;
95
+ /**
96
+ * @description The address where the transaction is sent from
97
+ * @protected
98
+ */
99
+ protected from: Address;
100
+ /**
101
+ * @description The maximum fee rate of the transaction
102
+ */
103
+ protected _maximumFeeRate: number = 100000000;
104
+
105
+ /**
106
+ * @param {ITransactionParameters} parameters - The transaction parameters
107
+ */
108
+ protected constructor(parameters: ITransactionParameters) {
109
+ super(parameters);
110
+
111
+ if (parameters.estimatedFees) {
112
+ this.estimatedFees = parameters.estimatedFees;
113
+ }
114
+
115
+ this.signer = parameters.signer;
116
+ this.network = parameters.network;
117
+ this.feeRate = parameters.feeRate;
118
+ this.priorityFee = parameters.priorityFee;
119
+ this.utxos = parameters.utxos;
120
+ this.to = parameters.to || undefined;
121
+
122
+ this.from = TransactionBuilder.getFrom(
123
+ parameters.from,
124
+ this.signer as ECPairInterface,
125
+ this.network,
126
+ );
127
+
128
+ this.totalInputAmount = this.calculateTotalUTXOAmount();
129
+
130
+ const totalVOut: bigint = this.calculateTotalVOutAmount();
131
+ if (totalVOut < this.totalInputAmount) {
132
+ throw new Error(`Vout value is less than the value to send`);
133
+ }
134
+
135
+ this.transaction = new Psbt({
136
+ network: this.network,
137
+ });
138
+ }
139
+
140
+ public static getFrom(
141
+ from: string | undefined,
142
+ keypair: ECPairInterface,
143
+ network: Network,
144
+ ): Address {
145
+ return from || EcKeyPair.getTaprootAddress(keypair, network);
146
+ }
147
+
148
+ /**
149
+ * @description Converts the witness stack to a script witness
150
+ * @param {Buffer[]} witness - The witness stack
151
+ * @protected
152
+ * @returns {Buffer}
153
+ */
154
+ public static witnessStackToScriptWitness(witness: Buffer[]): Buffer {
155
+ let buffer = Buffer.allocUnsafe(0);
156
+
157
+ function writeSlice(slice: Buffer) {
158
+ buffer = Buffer.concat([buffer, Buffer.from(slice)]);
159
+ }
160
+
161
+ function writeVarInt(i: number) {
162
+ const currentLen = buffer.length;
163
+ const varintLen = varuint.encodingLength(i);
164
+
165
+ buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
166
+ varuint.encode(i, buffer, currentLen);
167
+ }
168
+
169
+ function writeVarSlice(slice: Buffer) {
170
+ writeVarInt(slice.length);
171
+ writeSlice(slice);
172
+ }
173
+
174
+ function writeVector(vector: Buffer[]) {
175
+ writeVarInt(vector.length);
176
+ vector.forEach(writeVarSlice);
177
+ }
178
+
179
+ writeVector(witness);
180
+
181
+ return buffer;
182
+ }
183
+
184
+ public async getFundingTransactionParameters(): Promise<IFundingTransactionParameters> {
185
+ if (!this.estimatedFees) {
186
+ this.estimatedFees = await this.estimateTransactionFees();
187
+ }
188
+
189
+ return {
190
+ utxos: this.utxos,
191
+ to: this.getScriptAddress(),
192
+ signer: this.signer,
193
+ network: this.network,
194
+ feeRate: this.feeRate,
195
+ priorityFee: this.priorityFee,
196
+ from: this.from,
197
+ amount: this.estimatedFees,
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Set the destination address of the transaction
203
+ * @param {Address} address - The address to set
204
+ */
205
+ public setDestinationAddress(address: Address): void {
206
+ this.to = address; // this.getScriptAddress()
207
+ }
208
+
209
+ /**
210
+ * Set the maximum fee rate of the transaction in satoshis per byte
211
+ * @param {number} feeRate - The fee rate to set
212
+ * @public
213
+ */
214
+ public setMaximumFeeRate(feeRate: number): void {
215
+ this._maximumFeeRate = feeRate;
216
+ }
217
+
218
+ /**
219
+ * @description Signs the transaction
220
+ * @public
221
+ * @returns {Promise<Transaction>} - The signed transaction in hex format
222
+ * @throws {Error} - If something went wrong
223
+ */
224
+ public async signTransaction(): Promise<Transaction> {
225
+ if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
226
+ throw new Error(
227
+ 'Invalid contract address. The contract address must be a taproot address.',
228
+ );
229
+ }
230
+
231
+ if (this.signed) throw new Error('Transaction is already signed');
232
+ this.signed = true;
233
+
234
+ await this.buildTransaction();
235
+
236
+ const builtTx = await this.internalBuildTransaction(this.transaction);
237
+ if (builtTx) {
238
+ if (this.regenerated) {
239
+ throw new Error('Transaction was regenerated');
240
+ }
241
+
242
+ return this.transaction.extractTransaction(false);
243
+ }
244
+
245
+ throw new Error('Could not sign transaction');
246
+ }
247
+
248
+ /**
249
+ * @description Generates the transaction minimal signatures
250
+ * @public
251
+ */
252
+ public async generateTransactionMinimalSignatures(): Promise<void> {
253
+ if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
254
+ throw new Error(
255
+ 'Invalid contract address. The contract address must be a taproot address.',
256
+ );
257
+ }
258
+
259
+ await this.buildTransaction();
260
+
261
+ if (this.transaction.data.inputs.length === 0) {
262
+ const inputs: PsbtInputExtended[] = this.getInputs();
263
+ const outputs: PsbtOutputExtended[] = this.getOutputs();
264
+
265
+ this.transaction.setMaximumFeeRate(this._maximumFeeRate);
266
+ this.transaction.addInputs(inputs);
267
+
268
+ for (let i = 0; i < this.updateInputs.length; i++) {
269
+ this.transaction.updateInput(i, this.updateInputs[i]);
270
+ }
271
+
272
+ this.transaction.addOutputs(outputs);
273
+ }
274
+ }
275
+
276
+ /**
277
+ * @description Signs the transaction
278
+ * @public
279
+ * @returns {Promise<Psbt>} - The signed transaction in hex format
280
+ * @throws {Error} - If something went wrong
281
+ */
282
+ public async signPSBT(): Promise<Psbt> {
283
+ if (await this.signTransaction()) {
284
+ return this.transaction;
285
+ }
286
+
287
+ throw new Error('Could not sign transaction');
288
+ }
289
+
290
+ /**
291
+ * Add an input to the transaction.
292
+ * @param {PsbtInputExtended} input - The input to add
293
+ * @public
294
+ * @returns {void}
295
+ */
296
+ public addInput(input: PsbtInputExtended): void {
297
+ this.inputs.push(input);
298
+ }
299
+
300
+ /**
301
+ * Add an output to the transaction.
302
+ * @param {PsbtOutputExtended} output - The output to add
303
+ * @public
304
+ * @returns {void}
305
+ */
306
+ public addOutput(output: PsbtOutputExtended): void {
307
+ if (output.value === 0) return;
308
+ if (output.value < TransactionBuilder.MINIMUM_DUST) {
309
+ throw new Error(
310
+ `Output value is less than the minimum dust ${output.value} < ${TransactionBuilder.MINIMUM_DUST}`,
311
+ );
312
+ }
313
+
314
+ this.outputs.push(output);
315
+ }
316
+
317
+ /**
318
+ * Receiver address.
319
+ * @public
320
+ * @returns {Address} - The receiver address
321
+ */
322
+ public toAddress(): string | undefined {
323
+ return this.to;
324
+ }
325
+
326
+ /**
327
+ * @description Returns the script address
328
+ * @returns {Address} - The script address
329
+ */
330
+ public address(): Address | undefined {
331
+ return this.tapData?.address;
332
+ }
333
+
334
+ /**
335
+ * Estimates the transaction fees.
336
+ * @public
337
+ * @returns {Promise<bigint>} - The estimated transaction fees
338
+ */
339
+ public async estimateTransactionFees(): Promise<bigint> {
340
+ if (this.estimatedFees) return this.estimatedFees;
341
+
342
+ const fakeTx = new Psbt({
343
+ network: this.network,
344
+ });
345
+
346
+ const builtTx = await this.internalBuildTransaction(fakeTx);
347
+ if (builtTx) {
348
+ const tx = fakeTx.extractTransaction(true, true);
349
+ const size = tx.virtualSize();
350
+ const fee: number = this.feeRate * size;
351
+
352
+ this.estimatedFees = BigInt(Math.ceil(fee) + 1);
353
+
354
+ return this.estimatedFees;
355
+ } else {
356
+ throw new Error(
357
+ `Could not build transaction to estimate fee. Something went wrong while building the transaction.`,
358
+ );
359
+ }
360
+ }
361
+
362
+ public async rebuildFromBase64(base64: string): Promise<Psbt> {
363
+ this.transaction = Psbt.fromBase64(base64, { network: this.network });
364
+ this.signed = false;
365
+
366
+ this.sighashTypes = [Transaction.SIGHASH_ANYONECANPAY, Transaction.SIGHASH_ALL];
367
+
368
+ return await this.signPSBT();
369
+ }
370
+
371
+ public setPSBT(psbt: Psbt): void {
372
+ this.transaction = psbt;
373
+ }
374
+
375
+ /**
376
+ * @description Adds the refund output to the transaction
377
+ * @param {bigint} amountSpent - The amount spent
378
+ * @protected
379
+ * @returns {Promise<void>}
380
+ */
381
+ protected async addRefundOutput(amountSpent: bigint): Promise<void> {
382
+ /** Add the refund output */
383
+ const sendBackAmount: bigint = this.totalInputAmount - amountSpent;
384
+ if (sendBackAmount >= TransactionBuilder.MINIMUM_DUST) {
385
+ if (AddressVerificator.isValidP2TRAddress(this.from, this.network)) {
386
+ await this.setFeeOutput({
387
+ value: Number(sendBackAmount),
388
+ address: this.from,
389
+ tapInternalKey: this.internalPubKeyToXOnly(),
390
+ });
391
+ } else {
392
+ await this.setFeeOutput({
393
+ value: Number(sendBackAmount),
394
+ address: this.from,
395
+ });
396
+ }
397
+
398
+ return;
399
+ }
400
+
401
+ this.warn(
402
+ `Amount to send back (${sendBackAmount} sat) is less than the minimum dust (${TransactionBuilder.MINIMUM_DUST} sat), it will be consumed in fees instead.`,
403
+ );
404
+ }
405
+
406
+ /**
407
+ * @description Adds the value to the output
408
+ * @param {number | bigint} value - The value to add
409
+ * @protected
410
+ * @returns {void}
411
+ */
412
+ protected addValueToToOutput(value: number | bigint): void {
413
+ if (value < TransactionBuilder.MINIMUM_DUST) {
414
+ throw new Error(
415
+ `Value to send is less than the minimum dust ${value} < ${TransactionBuilder.MINIMUM_DUST}`,
416
+ );
417
+ }
418
+
419
+ for (let output of this.outputs) {
420
+ if ('address' in output && output.address === this.to) {
421
+ output.value += Number(value);
422
+ return;
423
+ }
424
+ }
425
+
426
+ throw new Error('Output not found');
427
+ }
428
+
429
+ /**
430
+ * @description Returns the transaction opnet fee
431
+ * @protected
432
+ * @returns {bigint}
433
+ */
434
+ protected getTransactionOPNetFee(): bigint {
435
+ if (this.priorityFee > TransactionBuilder.MINIMUM_DUST) {
436
+ return this.priorityFee;
437
+ }
438
+
439
+ return TransactionBuilder.MINIMUM_DUST;
440
+ }
441
+
442
+ /**
443
+ * @description Returns the total amount of satoshis in the inputs
444
+ * @protected
445
+ * @returns {bigint}
446
+ */
447
+ protected calculateTotalUTXOAmount(): bigint {
448
+ let total: bigint = 0n;
449
+ for (let utxo of this.utxos) {
450
+ total += utxo.value;
451
+ }
452
+
453
+ return total;
454
+ }
455
+
456
+ /**
457
+ * @description Returns the total amount of satoshis in the outputs
458
+ * @protected
459
+ * @returns {bigint}
460
+ */
461
+ protected calculateTotalVOutAmount(): bigint {
462
+ let total: bigint = 0n;
463
+ for (let utxo of this.utxos) {
464
+ total += utxo.value;
465
+ }
466
+
467
+ return total;
468
+ }
469
+
470
+ /**
471
+ * @description Adds the inputs from the utxos
472
+ * @protected
473
+ * @returns {void}
474
+ */
475
+ protected addInputsFromUTXO(): void {
476
+ if (this.utxos.length) {
477
+ //throw new Error('No UTXOs specified');
478
+
479
+ if (this.totalInputAmount < TransactionBuilder.MINIMUM_DUST) {
480
+ throw new Error(
481
+ `Total input amount is ${this.totalInputAmount} sat which is less than the minimum dust ${TransactionBuilder.MINIMUM_DUST} sat.`,
482
+ );
483
+ }
484
+
485
+ for (let i = 0; i < this.utxos.length; i++) {
486
+ const utxo = this.utxos[i];
487
+ const input = this.generatePsbtInputExtended(utxo, i);
488
+
489
+ this.addInput(input);
490
+ }
491
+ }
492
+ }
493
+
494
+ /**
495
+ * Internal init.
496
+ * @protected
497
+ */
498
+ protected override internalInit(): void {
499
+ this.verifyUTXOValidity();
500
+
501
+ super.internalInit();
502
+ }
503
+
504
+ /**
505
+ * Builds the transaction.
506
+ * @protected
507
+ * @returns {Promise<void>}
508
+ */
509
+ protected abstract buildTransaction(): Promise<void>;
510
+
511
+ /**
512
+ * Add an input update
513
+ * @param {UpdateInput} input - The input to update
514
+ * @protected
515
+ * @returns {void}
516
+ */
517
+ protected updateInput(input: UpdateInput): void {
518
+ this.updateInputs.push(input);
519
+ }
520
+
521
+ /**
522
+ * Returns the witness of the tap transaction.
523
+ * @protected
524
+ * @returns {Buffer}
525
+ */
526
+ protected getWitness(): Buffer {
527
+ if (!this.tapData || !this.tapData.witness) {
528
+ throw new Error('Witness is required');
529
+ }
530
+
531
+ if (this.tapData.witness.length === 0) {
532
+ throw new Error('Witness is empty');
533
+ }
534
+
535
+ return this.tapData.witness[this.tapData.witness.length - 1];
536
+ }
537
+
538
+ /**
539
+ * Returns the tap output.
540
+ * @protected
541
+ * @returns {Buffer}
542
+ */
543
+ protected getTapOutput(): Buffer {
544
+ if (!this.tapData || !this.tapData.output) {
545
+ throw new Error('Tap data is required');
546
+ }
547
+
548
+ return this.tapData.output;
549
+ }
550
+
551
+ /**
552
+ * Returns the inputs of the transaction.
553
+ * @protected
554
+ * @returns {PsbtInputExtended[]}
555
+ */
556
+ protected getInputs(): PsbtInputExtended[] {
557
+ return this.inputs;
558
+ }
559
+
560
+ /**
561
+ * Returns the outputs of the transaction.
562
+ * @protected
563
+ * @returns {PsbtOutputExtended[]}
564
+ */
565
+ protected getOutputs(): PsbtOutputExtended[] {
566
+ const outputs: PsbtOutputExtended[] = [...this.outputs];
567
+ if (this.feeOutput) outputs.push(this.feeOutput);
568
+
569
+ return outputs;
570
+ }
571
+
572
+ /**
573
+ * Verifies that the utxos are valid.
574
+ * @protected
575
+ */
576
+ protected verifyUTXOValidity(): void {
577
+ for (let utxo of this.utxos) {
578
+ if (!utxo.scriptPubKey) {
579
+ throw new Error('Address is required');
580
+ }
581
+ }
582
+ }
583
+
584
+ /**
585
+ * Set transaction fee output.
586
+ * @param {PsbtOutputExtended} output - The output to set the fees
587
+ * @protected
588
+ * @returns {Promise<void>}
589
+ */
590
+ protected async setFeeOutput(output: PsbtOutputExtended): Promise<void> {
591
+ const initialValue = output.value;
592
+
593
+ let fee = await this.estimateTransactionFees();
594
+ output.value = initialValue - Number(fee);
595
+
596
+ if (output.value < TransactionBuilder.MINIMUM_DUST) {
597
+ this.feeOutput = null;
598
+
599
+ if (output.value < 0) {
600
+ throw new Error(
601
+ `setFeeOutput: Insufficient funds to pay the fees. Fee: ${fee} > Value: ${initialValue}. Total input: ${this.totalInputAmount} sat`,
602
+ );
603
+ }
604
+ } else {
605
+ this.feeOutput = output;
606
+
607
+ let fee = await this.estimateTransactionFees();
608
+ if (fee > BigInt(initialValue)) {
609
+ throw new Error(
610
+ `estimateTransactionFees: Insufficient funds to pay the fees. Fee: ${fee} > Value: ${initialValue}. Total input: ${this.totalInputAmount} sat`,
611
+ );
612
+ }
613
+
614
+ const valueLeft = initialValue - Number(fee);
615
+ if (valueLeft < TransactionBuilder.MINIMUM_DUST) {
616
+ this.feeOutput = null;
617
+ } else {
618
+ this.feeOutput.value = valueLeft;
619
+ }
620
+
621
+ this.overflowFees = BigInt(valueLeft);
622
+ }
623
+ }
624
+
625
+ /**
626
+ * Builds the transaction.
627
+ * @param {Psbt} transaction - The transaction to build
628
+ * @protected
629
+ * @returns {Promise<boolean>}
630
+ * @throws {Error} - If something went wrong while building the transaction
631
+ */
632
+ protected async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
633
+ if (transaction.data.inputs.length === 0) {
634
+ const inputs: PsbtInputExtended[] = this.getInputs();
635
+ const outputs: PsbtOutputExtended[] = this.getOutputs();
636
+
637
+ transaction.setMaximumFeeRate(this._maximumFeeRate);
638
+ transaction.addInputs(inputs);
639
+
640
+ for (let i = 0; i < this.updateInputs.length; i++) {
641
+ transaction.updateInput(i, this.updateInputs[i]);
642
+ }
643
+
644
+ transaction.addOutputs(outputs);
645
+ }
646
+
647
+ try {
648
+ await this.signInputs(transaction);
649
+
650
+ if (this.finalized) {
651
+ this.transactionFee = BigInt(transaction.getFee());
652
+ }
653
+
654
+ return true;
655
+ } catch (e) {
656
+ const err: Error = e as Error;
657
+
658
+ this.error(
659
+ `[internalBuildTransaction] Something went wrong while getting building the transaction: ${err.stack}`,
660
+ );
661
+ }
662
+
663
+ return false;
664
+ }
665
+ }