@btc-vision/transaction 1.0.97 → 1.0.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +4 -7
- package/.prettierrc.json +11 -11
- package/CONTRIBUTING.md +71 -71
- package/LICENSE.md +62 -62
- package/README.md +76 -76
- package/browser/_version.d.ts +1 -1
- package/browser/bytecode/Compressor.d.ts +0 -1
- package/browser/crypto/crypto-browser.d.ts +1 -30
- package/browser/crypto/crypto.d.ts +0 -1
- package/browser/generators/AddressGenerator.d.ts +0 -1
- package/browser/generators/Generator.d.ts +0 -1
- package/browser/generators/builders/CalldataGenerator.d.ts +0 -1
- package/browser/generators/builders/DeploymentGenerator.d.ts +0 -1
- package/browser/generators/builders/MultiSignGenerator.d.ts +0 -1
- package/browser/index.js +1 -1
- package/browser/keypair/EcKeyPair.d.ts +0 -1
- package/browser/keypair/Wallet.d.ts +0 -1
- package/browser/signer/TweakedSigner.d.ts +0 -1
- package/browser/transaction/browser/BrowserSignerBase.d.ts +0 -1
- package/browser/transaction/browser/extensions/UnisatSigner.d.ts +0 -1
- package/browser/transaction/builders/DeploymentTransaction.d.ts +0 -1
- package/browser/transaction/builders/InteractionTransaction.d.ts +0 -1
- package/browser/transaction/builders/MultiSignTransaction.d.ts +0 -1
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +0 -1
- package/browser/transaction/builders/TransactionBuilder.d.ts +0 -1
- package/browser/transaction/builders/UnwrapSegwitTransaction.d.ts +0 -1
- package/browser/transaction/builders/UnwrapTransaction.d.ts +0 -1
- package/browser/transaction/builders/WrapTransaction.d.ts +0 -1
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +0 -1
- package/browser/transaction/interfaces/Tap.d.ts +0 -1
- package/browser/transaction/shared/P2TR_MS.d.ts +0 -1
- package/browser/transaction/shared/TweakedTransaction.d.ts +0 -1
- package/browser/utils/BitcoinUtils.d.ts +0 -1
- package/browser/verification/TapscriptVerificator.d.ts +0 -1
- package/browser/wbtc/WrappedGenerationParameters.d.ts +0 -1
- package/build/bytecode/Compressor.d.ts +0 -1
- package/build/bytecode/Compressor.js +4 -4
- package/build/crypto/crypto.d.ts +0 -1
- package/build/generators/AddressGenerator.d.ts +0 -1
- package/build/generators/Generator.d.ts +0 -1
- package/build/generators/Generator.js +3 -5
- package/build/generators/builders/CalldataGenerator.d.ts +0 -1
- package/build/generators/builders/DeploymentGenerator.d.ts +0 -1
- package/build/generators/builders/{MultisignGenerator.d.ts → MultiSignGenerator.d.ts} +0 -1
- package/build/generators/builders/{MultisignGenerator.js → MultiSignGenerator.js} +1 -1
- package/build/keypair/EcKeyPair.d.ts +0 -1
- package/build/keypair/EcKeyPair.js +2 -2
- package/build/keypair/Wallet.d.ts +0 -1
- package/build/keypair/Wallet.js +0 -5
- package/build/metadata/ContractBaseMetadata.js +0 -1
- package/build/metadata/contracts/wBTC.js +3 -5
- package/build/metadata/tokens.js +27 -25
- package/build/signer/TweakedSigner.d.ts +0 -1
- package/build/transaction/browser/BrowserSignerBase.d.ts +0 -1
- package/build/transaction/browser/extensions/UnisatSigner.d.ts +0 -1
- package/build/transaction/browser/extensions/UnisatSigner.js +1 -6
- package/build/transaction/builders/DeploymentTransaction.d.ts +0 -1
- package/build/transaction/builders/DeploymentTransaction.js +25 -33
- package/build/transaction/builders/FundingTransaction.js +1 -3
- package/build/transaction/builders/InteractionTransaction.d.ts +0 -1
- package/build/transaction/builders/InteractionTransaction.js +2 -5
- package/build/transaction/builders/MultiSignTransaction.d.ts +0 -1
- package/build/transaction/builders/MultiSignTransaction.js +66 -73
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +0 -1
- package/build/transaction/builders/SharedInteractionTransaction.js +20 -25
- package/build/transaction/builders/TransactionBuilder.d.ts +0 -1
- package/build/transaction/builders/TransactionBuilder.js +12 -21
- package/build/transaction/builders/UnwrapSegwitTransaction.d.ts +0 -1
- package/build/transaction/builders/UnwrapSegwitTransaction.js +4 -10
- package/build/transaction/builders/UnwrapTransaction.d.ts +0 -1
- package/build/transaction/builders/UnwrapTransaction.js +5 -11
- package/build/transaction/builders/WrapTransaction.d.ts +0 -1
- package/build/transaction/builders/WrapTransaction.js +5 -12
- package/build/transaction/interfaces/ITransactionParameters.d.ts +0 -1
- package/build/transaction/interfaces/Tap.d.ts +0 -1
- package/build/transaction/processor/PsbtTransaction.js +3 -4
- package/build/transaction/shared/P2TR_MS.d.ts +0 -1
- package/build/transaction/shared/TweakedTransaction.d.ts +0 -1
- package/build/transaction/shared/TweakedTransaction.js +11 -16
- package/build/utils/BitcoinUtils.d.ts +0 -1
- package/build/utxo/OPNetLimitedProvider.js +2 -3
- package/build/verification/TapscriptVerificator.d.ts +0 -1
- package/build/verification/TapscriptVerificator.js +1 -1
- package/build/wbtc/UnwrapGeneration.js +0 -2
- package/build/wbtc/WrappedGenerationParameters.d.ts +0 -1
- package/build/wbtc/WrappedGenerationParameters.js +0 -6
- package/cjs/package.json +3 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/highlight.css +43 -0
- package/docs/assets/icons.js +15 -0
- package/docs/assets/icons.svg +1 -0
- package/docs/assets/main.js +59 -0
- package/docs/assets/material-style.css +247 -0
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1412 -0
- package/docs/classes/AddressGenerator.html +177 -0
- package/docs/classes/AddressVerificator.html +177 -0
- package/docs/classes/BitcoinUtils.html +196 -0
- package/docs/classes/CalldataGenerator.html +213 -0
- package/docs/classes/Compressor.html +185 -0
- package/docs/classes/ContractBaseMetadata.html +182 -0
- package/docs/classes/CustomKeypair.html +189 -0
- package/docs/classes/DeploymentGenerator.html +201 -0
- package/docs/classes/DeploymentTransaction.html +465 -0
- package/docs/classes/EcKeyPair.html +280 -0
- package/docs/classes/FundingTransaction.html +425 -0
- package/docs/classes/Generator.html +199 -0
- package/docs/classes/InteractionTransaction.html +467 -0
- package/docs/classes/MultiSignGenerator.html +178 -0
- package/docs/classes/MultiSignTransaction.html +490 -0
- package/docs/classes/OPNetLimitedProvider.html +225 -0
- package/docs/classes/OPNetTokenAddressManager.html +182 -0
- package/docs/classes/P2TR_MS.html +186 -0
- package/docs/classes/PsbtTransaction.html +320 -0
- package/docs/classes/SharedInteractionTransaction.html +477 -0
- package/docs/classes/TapscriptVerificator.html +180 -0
- package/docs/classes/TransactionBuilder.html +423 -0
- package/docs/classes/TransactionFactory.html +230 -0
- package/docs/classes/TweakedSigner.html +181 -0
- package/docs/classes/TweakedTransaction.html +301 -0
- package/docs/classes/UnisatSigner.html +199 -0
- package/docs/classes/UnwrapGeneration.html +177 -0
- package/docs/classes/UnwrapTransaction.html +518 -0
- package/docs/classes/Wallet.html +204 -0
- package/docs/classes/WrapTransaction.html +509 -0
- package/docs/classes/WrappedGeneration.html +187 -0
- package/docs/classes/wBTC.html +190 -0
- package/docs/enums/ChainId.html +176 -0
- package/docs/enums/Consensus.html +204 -0
- package/docs/enums/Features.html +175 -0
- package/docs/enums/MessageType.html +176 -0
- package/docs/enums/OPNetNetwork.html +177 -0
- package/docs/enums/PSBTTypes.html +175 -0
- package/docs/enums/TransactionSequence.html +177 -0
- package/docs/enums/TransactionType.html +181 -0
- package/docs/enums/UnisatChainType.html +181 -0
- package/docs/enums/UnisatNetwork.html +177 -0
- package/docs/hierarchy.html +174 -0
- package/docs/index.html +215 -0
- package/docs/interfaces/Balance.html +177 -0
- package/docs/interfaces/BitcoinTransferResponse.html +178 -0
- package/docs/interfaces/BroadcastResponse.html +181 -0
- package/docs/interfaces/BroadcastTransactionOptions.html +176 -0
- package/docs/interfaces/BroadcastedTransaction.html +184 -0
- package/docs/interfaces/ConsensusConfig.html +182 -0
- package/docs/interfaces/ContractAddressVerificationParams.html +179 -0
- package/docs/interfaces/DeploymentResult.html +178 -0
- package/docs/interfaces/FetchUTXOParams.html +178 -0
- package/docs/interfaces/FetchUTXOParamsMultiAddress.html +178 -0
- package/docs/interfaces/FundingTransactionResponse.html +178 -0
- package/docs/interfaces/GenerationConstraints.html +182 -0
- package/docs/interfaces/IDeploymentParameters.html +186 -0
- package/docs/interfaces/IFundingTransactionParameters.html +186 -0
- package/docs/interfaces/IInteractionParameters.html +187 -0
- package/docs/interfaces/ITransactionParameters.html +184 -0
- package/docs/interfaces/ITweakedTransactionData.html +178 -0
- package/docs/interfaces/IUnwrapParameters.html +189 -0
- package/docs/interfaces/IWBTCUTXODocument.html +180 -0
- package/docs/interfaces/IWallet.html +181 -0
- package/docs/interfaces/IWrapParameters.html +190 -0
- package/docs/interfaces/MultiSignFromBase64Params.html +188 -0
- package/docs/interfaces/MultiSignParameters.html +188 -0
- package/docs/interfaces/OPNetTokenMetadata.html +179 -0
- package/docs/interfaces/PsbtInputExtended.html +194 -0
- package/docs/interfaces/PsbtOutputExtendedAddress.html +183 -0
- package/docs/interfaces/PsbtOutputExtendedScript.html +183 -0
- package/docs/interfaces/PsbtSignatureOptions.html +176 -0
- package/docs/interfaces/PsbtTransactionData.html +179 -0
- package/docs/interfaces/RawUTXOResponse.html +178 -0
- package/docs/interfaces/SharedInteractionParameters.html +187 -0
- package/docs/interfaces/TapLeafScript.html +177 -0
- package/docs/interfaces/ToSignInputAddress.html +178 -0
- package/docs/interfaces/ToSignInputPublicKey.html +178 -0
- package/docs/interfaces/TweakSettings.html +179 -0
- package/docs/interfaces/UTXO.html +178 -0
- package/docs/interfaces/Unisat.html +190 -0
- package/docs/interfaces/UnisatChainInfo.html +177 -0
- package/docs/interfaces/UnwrapResult.html +181 -0
- package/docs/interfaces/UnwrappedGenerationParameters.html +178 -0
- package/docs/interfaces/UpdateInput.html +175 -0
- package/docs/interfaces/VaultUTXOs.html +178 -0
- package/docs/interfaces/Web3Provider.html +180 -0
- package/docs/interfaces/WrapResult.html +179 -0
- package/docs/interfaces/WrappedGenerationParameters.html +184 -0
- package/docs/modules.html +289 -0
- package/docs/types/FromBase64Params.html +174 -0
- package/docs/types/IDeploymentParametersWithoutSigner.html +174 -0
- package/docs/types/IUnwrapParametersWithoutSigner.html +174 -0
- package/docs/types/IWrapParametersWithoutSigner.html +174 -0
- package/docs/types/InteractionParametersWithoutSigner.html +174 -0
- package/docs/types/PsbtOutputExtended.html +174 -0
- package/docs/types/ToSignInput.html +174 -0
- package/docs/variables/FACTORY_ADDRESS_FRACTAL.html +174 -0
- package/docs/variables/FACTORY_ADDRESS_REGTEST.html +174 -0
- package/docs/variables/FACTORY_ADDRESS_TESTNET.html +174 -0
- package/docs/variables/MOTO_ADDRESS_FRACTAL.html +174 -0
- package/docs/variables/MOTO_ADDRESS_REGTEST.html +174 -0
- package/docs/variables/MOTO_ADDRESS_TESTNET.html +174 -0
- package/docs/variables/OPNetConsensusConfig.html +174 -0
- package/docs/variables/OPNetMetadata.html +174 -0
- package/docs/variables/POOL_ADDRESS_FRACTAL.html +174 -0
- package/docs/variables/POOL_ADDRESS_REGTEST.html +174 -0
- package/docs/variables/POOL_ADDRESS_TESTNET.html +174 -0
- package/docs/variables/ROUTER_ADDRESS_FRACTAL.html +174 -0
- package/docs/variables/ROUTER_ADDRESS_REGTEST.html +174 -0
- package/docs/variables/ROUTER_ADDRESS_TESTNET.html +174 -0
- package/docs/variables/RoswellConsensus.html +174 -0
- package/docs/variables/WBTC_ADDRESS_FRACTAL.html +174 -0
- package/docs/variables/WBTC_ADDRESS_REGTEST.html +174 -0
- package/docs/variables/WBTC_ADDRESS_TESTNET.html +174 -0
- package/docs/variables/currentConsensus.html +174 -0
- package/docs/variables/currentConsensusConfig.html +174 -0
- package/docs/variables/version.html +174 -0
- package/gulpfile.js +49 -133
- package/package.json +112 -113
- package/src/bytecode/Compressor.ts +27 -27
- package/src/consensus/metadata/RoswellConsensus.ts +26 -26
- package/src/crypto/crypto.ts +1 -1
- package/src/generators/Generator.ts +75 -75
- package/src/generators/builders/MultiSignGenerator.ts +73 -73
- package/src/metadata/contracts/wBTC.ts +60 -60
- package/src/metadata/tokens.ts +135 -135
- package/src/network/ChainId.ts +6 -6
- package/src/opnet.ts +82 -82
- package/src/signer/TweakedSigner.ts +56 -56
- package/src/transaction/builders/DeploymentTransaction.ts +356 -356
- package/src/transaction/builders/MultiSignTransaction.ts +659 -659
- package/src/transaction/builders/UnwrapSegwitTransaction.ts +365 -365
- package/src/transaction/builders/UnwrapTransaction.ts +507 -507
- package/src/transaction/enums/TransactionType.ts +9 -9
- package/src/transaction/processor/PsbtTransaction.ts +173 -173
- package/src/transaction/shared/P2TR_MS.ts +42 -42
- package/src/transaction/shared/TweakedTransaction.ts +539 -539
- package/src/utils/BitcoinUtils.ts +96 -96
- package/tsconfig.base.json +27 -43
- package/tsconfig.json +15 -8
- package/tsconfig.webpack.json +22 -22
- package/EPOCH.md +0 -250
- package/VAULT_TARGET_CONSOLIDATION.md +0 -111
- package/browser/network/NetworkInformation.d.ts +0 -6
- package/browser/transaction/browser/BrowserSigner.d.ts +0 -9
- package/browser/transaction/builders/TapUnwarpTransaction.d.ts +0 -40
- package/browser/transaction/builders/UnwarpTransaction.d.ts +0 -34
- package/browser/utxo/UTXOManager.d.ts +0 -7
- package/build/Utils.d.ts +0 -0
- package/build/Utils.js +0 -1
- package/build/consensus/metadata/RoswsellConsensus.d.ts +0 -2
- package/build/consensus/metadata/RoswsellConsensus.js +0 -4
- package/build/contracts/ContractMetadataManager.d.ts +0 -0
- package/build/contracts/ContractMetadataManager.js +0 -1
- package/build/generators/OPNetAddressGenerator.d.ts +0 -0
- package/build/generators/OPNetAddressGenerator.js +0 -1
- package/build/generators/builders/DeploymentGeneratorV2.d.ts +0 -13
- package/build/generators/builders/DeploymentGeneratorV2.js +0 -57
- package/build/generators/builders/UnwrapGenerator.d.ts +0 -8
- package/build/generators/builders/UnwrapGenerator.js +0 -79
- package/build/keypair/interfaces/GeneratedWallet.d.ts +0 -5
- package/build/keypair/interfaces/GeneratedWallet.js +0 -1
- package/build/metadata/CommonContracts.d.ts +0 -6
- package/build/metadata/CommonContracts.js +0 -5
- package/build/metadata/ContractMetadataManager.d.ts +0 -1
- package/build/metadata/ContractMetadataManager.js +0 -9
- package/build/metadata/contracts/ContractBase.d.ts +0 -9
- package/build/metadata/contracts/ContractBase.js +0 -13
- package/build/metadata/contracts/ContractBaseMetadata.d.ts +0 -9
- package/build/metadata/contracts/ContractBaseMetadata.js +0 -13
- package/build/metadata/contracts/ContractMetadataManager.d.ts +0 -0
- package/build/metadata/contracts/ContractMetadataManager.js +0 -1
- package/build/network/NetworkConverter.d.ts +0 -0
- package/build/network/NetworkConverter.js +0 -14
- package/build/network/NetworkInformation.d.ts +0 -6
- package/build/network/NetworkInformation.js +0 -1
- package/build/scripts/Regtest.d.ts +0 -2
- package/build/scripts/Regtest.js +0 -15
- package/build/scripts/test.d.ts +0 -1
- package/build/scripts/test.js +0 -74
- package/build/signer/Regtest.d.ts +0 -2
- package/build/signer/Regtest.js +0 -15
- package/build/tests/Regtest.d.ts +0 -3
- package/build/tests/Regtest.js +0 -29
- package/build/tests/adaptPSBT.d.ts +0 -1
- package/build/tests/adaptPSBT.js +0 -44
- package/build/tests/btc/send.d.ts +0 -1
- package/build/tests/btc/send.js +0 -35
- package/build/tests/btc/transfer.d.ts +0 -1
- package/build/tests/btc/transfer.js +0 -35
- package/build/tests/createPairReg.d.ts +0 -1
- package/build/tests/createPairReg.js +0 -73
- package/build/tests/deploy/deployMoto.d.ts +0 -4
- package/build/tests/deploy/deployMoto.js +0 -89
- package/build/tests/deploy/deployPool.d.ts +0 -1
- package/build/tests/deploy/deployPool.js +0 -5
- package/build/tests/deploy/deployStep1.d.ts +0 -1
- package/build/tests/deploy/deployStep1.js +0 -5
- package/build/tests/deploy/deployStep2.d.ts +0 -1
- package/build/tests/deploy/deployStep2.js +0 -5
- package/build/tests/deploy/deployStep3.d.ts +0 -1
- package/build/tests/deploy/deployStep3.js +0 -5
- package/build/tests/deploy.d.ts +0 -1
- package/build/tests/deploy.js +0 -41
- package/build/tests/deployMotoRegStep1.d.ts +0 -1
- package/build/tests/deployMotoRegStep1.js +0 -85
- package/build/tests/deployReg.d.ts +0 -1
- package/build/tests/deployReg.js +0 -85
- package/build/tests/factory/createPairReg.d.ts +0 -1
- package/build/tests/factory/createPairReg.js +0 -13
- package/build/tests/gen.d.ts +0 -1
- package/build/tests/gen.js +0 -19
- package/build/tests/interaction.d.ts +0 -5
- package/build/tests/interaction.js +0 -62
- package/build/tests/massWrapReg.d.ts +0 -1
- package/build/tests/massWrapReg.js +0 -105
- package/build/tests/mineReg.d.ts +0 -1
- package/build/tests/mineReg.js +0 -19
- package/build/tests/moto/airdropToken.d.ts +0 -1
- package/build/tests/moto/airdropToken.js +0 -21
- package/build/tests/moto/airdropTokens.d.ts +0 -1
- package/build/tests/moto/airdropTokens.js +0 -60
- package/build/tests/moto/allowance.d.ts +0 -1
- package/build/tests/moto/allowance.js +0 -6
- package/build/tests/moto/approve.d.ts +0 -1
- package/build/tests/moto/approve.js +0 -10
- package/build/tests/moto/approveWBTC.d.ts +0 -1
- package/build/tests/moto/approveWBTC.js +0 -12
- package/build/tests/moto/balanceOf.d.ts +0 -1
- package/build/tests/moto/balanceOf.js +0 -12
- package/build/tests/moto/transfer.d.ts +0 -1
- package/build/tests/moto/transfer.js +0 -16
- package/build/tests/motoswap/airdropToken.d.ts +0 -11
- package/build/tests/motoswap/airdropToken.js +0 -36
- package/build/tests/motoswap/deployMoto.d.ts +0 -4
- package/build/tests/motoswap/deployMoto.js +0 -89
- package/build/tests/motoswap/deployMotoRegStep1.d.ts +0 -1
- package/build/tests/motoswap/deployMotoRegStep1.js +0 -91
- package/build/tests/motoswap/deployMotoRegStep2.d.ts +0 -1
- package/build/tests/motoswap/deployMotoRegStep2.js +0 -91
- package/build/tests/motoswap/deployPool.d.ts +0 -1
- package/build/tests/motoswap/deployPool.js +0 -5
- package/build/tests/motoswap/deployStep1.d.ts +0 -1
- package/build/tests/motoswap/deployStep1.js +0 -5
- package/build/tests/motoswap/deployStep2.d.ts +0 -1
- package/build/tests/motoswap/deployStep2.js +0 -5
- package/build/tests/motoswap/deployStep3.d.ts +0 -1
- package/build/tests/motoswap/deployStep3.js +0 -5
- package/build/tests/motoswap/interaction.d.ts +0 -3
- package/build/tests/motoswap/interaction.js +0 -63
- package/build/tests/motoswap/routerAddLiquidity.d.ts +0 -11
- package/build/tests/motoswap/routerAddLiquidity.js +0 -35
- package/build/tests/motoswap-router/addLiquidity.d.ts +0 -11
- package/build/tests/motoswap-router/addLiquidity.js +0 -36
- package/build/tests/motoswap-router/deployMoto.d.ts +0 -4
- package/build/tests/motoswap-router/deployMoto.js +0 -89
- package/build/tests/motoswap-router/deployPool.d.ts +0 -1
- package/build/tests/motoswap-router/deployPool.js +0 -5
- package/build/tests/motoswap-router/deployStep1.d.ts +0 -1
- package/build/tests/motoswap-router/deployStep1.js +0 -5
- package/build/tests/motoswap-router/deployStep2.d.ts +0 -1
- package/build/tests/motoswap-router/deployStep2.js +0 -5
- package/build/tests/motoswap-router/deployStep3.d.ts +0 -1
- package/build/tests/motoswap-router/deployStep3.js +0 -5
- package/build/tests/motoswap-router/getAmountsOut.d.ts +0 -5
- package/build/tests/motoswap-router/getAmountsOut.js +0 -34
- package/build/tests/motoswap-router/routerAddLiquidity.d.ts +0 -11
- package/build/tests/motoswap-router/routerAddLiquidity.js +0 -35
- package/build/tests/motoswap-router/swap.d.ts +0 -8
- package/build/tests/motoswap-router/swap.js +0 -24
- package/build/tests/multisign.d.ts +0 -1
- package/build/tests/multisign.js +0 -47
- package/build/tests/multisign2.d.ts +0 -1
- package/build/tests/multisign2.js +0 -27
- package/build/tests/pool/DecodePoolAddress.d.ts +0 -6
- package/build/tests/pool/DecodePoolAddress.js +0 -12
- package/build/tests/pool/decodeReserves.d.ts +0 -5
- package/build/tests/pool/decodeReserves.js +0 -13
- package/build/tests/pool/reserves.d.ts +0 -1
- package/build/tests/pool/reserves.js +0 -18
- package/build/tests/shared/Utils.d.ts +0 -2
- package/build/tests/shared/Utils.js +0 -14
- package/build/tests/shared/interaction.d.ts +0 -7
- package/build/tests/shared/interaction.js +0 -85
- package/build/tests/shared/tokens.d.ts +0 -6
- package/build/tests/shared/tokens.js +0 -5
- package/build/tests/stakeReg.d.ts +0 -1
- package/build/tests/stakeReg.js +0 -73
- package/build/tests/stakedReg.d.ts +0 -1
- package/build/tests/stakedReg.js +0 -28
- package/build/tests/test.d.ts +0 -1
- package/build/tests/test.js +0 -51
- package/build/tests/test2.d.ts +0 -1
- package/build/tests/test2.js +0 -73
- package/build/tests/testReg.d.ts +0 -1
- package/build/tests/testReg.js +0 -91
- package/build/tests/tokens.d.ts +0 -6
- package/build/tests/tokens.js +0 -5
- package/build/tests/totalRewardReg.d.ts +0 -1
- package/build/tests/totalRewardReg.js +0 -28
- package/build/tests/transfer.d.ts +0 -1
- package/build/tests/transfer.js +0 -74
- package/build/tests/transferReg.d.ts +0 -1
- package/build/tests/transferReg.js +0 -74
- package/build/tests/unStakeReg.d.ts +0 -1
- package/build/tests/unStakeReg.js +0 -72
- package/build/tests/unwrapReg.d.ts +0 -1
- package/build/tests/unwrapReg.js +0 -61
- package/build/tests/unwrapReg2.d.ts +0 -1
- package/build/tests/unwrapReg2.js +0 -56
- package/build/tests/unwrapRegSegwit.d.ts +0 -1
- package/build/tests/unwrapRegSegwit.js +0 -83
- package/build/tests/wbtc/approve.d.ts +0 -1
- package/build/tests/wbtc/approve.js +0 -6
- package/build/tests/wbtc/approveWBTC.d.ts +0 -1
- package/build/tests/wbtc/approveWBTC.js +0 -12
- package/build/tests/wbtc/massWrapReg.d.ts +0 -1
- package/build/tests/wbtc/massWrapReg.js +0 -105
- package/build/tests/wbtc/transfer.d.ts +0 -1
- package/build/tests/wbtc/transfer.js +0 -16
- package/build/tests/wbtc/transferReg.d.ts +0 -1
- package/build/tests/wbtc/transferReg.js +0 -16
- package/build/tests/wbtc/unStakeReg.d.ts +0 -1
- package/build/tests/wbtc/unStakeReg.js +0 -72
- package/build/tests/wbtc/unwrapReg.d.ts +0 -1
- package/build/tests/wbtc/unwrapReg.js +0 -60
- package/build/tests/wbtc/unwrapRegSegwit.d.ts +0 -1
- package/build/tests/wbtc/unwrapRegSegwit.js +0 -83
- package/build/tests/wbtc/withdrawalRequestReg.d.ts +0 -1
- package/build/tests/wbtc/withdrawalRequestReg.js +0 -71
- package/build/tests/wbtc/wrapReg.d.ts +0 -1
- package/build/tests/wbtc/wrapReg.js +0 -65
- package/build/tests/wbtc/wrapTest.d.ts +0 -1
- package/build/tests/wbtc/wrapTest.js +0 -66
- package/build/tests/withdrawalRequestReg.d.ts +0 -1
- package/build/tests/withdrawalRequestReg.js +0 -71
- package/build/tests/wrap.d.ts +0 -1
- package/build/tests/wrap.js +0 -65
- package/build/tests/wrapReg.d.ts +0 -1
- package/build/tests/wrapReg.js +0 -68
- package/build/tests/wrapTest.d.ts +0 -1
- package/build/tests/wrapTest.js +0 -66
- package/build/tests/wrapTestg.d.ts +0 -1
- package/build/tests/wrapTestg.js +0 -66
- package/build/tests/writers/allowance.d.ts +0 -3
- package/build/tests/writers/allowance.js +0 -10
- package/build/tests/writers/approve.d.ts +0 -4
- package/build/tests/writers/approve.js +0 -11
- package/build/transaction/TransactionBuilder.d.ts +0 -60
- package/build/transaction/TransactionBuilder.js +0 -244
- package/build/transaction/browser/BrowserSigner.d.ts +0 -11
- package/build/transaction/browser/BrowserSigner.js +0 -10
- package/build/transaction/browser/extensions/Unisat.d.ts +0 -54
- package/build/transaction/browser/extensions/Unisat.js +0 -11
- package/build/transaction/builders/DeploymentTransactionV2.d.ts +0 -36
- package/build/transaction/builders/DeploymentTransactionV2.js +0 -192
- package/build/transaction/builders/GenericTransaction.d.ts +0 -11
- package/build/transaction/builders/GenericTransaction.js +0 -23
- package/build/transaction/builders/TapUnwarpTransaction.d.ts +0 -37
- package/build/transaction/builders/TapUnwarpTransaction.js +0 -201
- package/build/transaction/builders/UnwarpSegwitTransaction.d.ts +0 -34
- package/build/transaction/builders/UnwarpSegwitTransaction.js +0 -184
- package/build/transaction/builders/UnwarpTransaction.d.ts +0 -35
- package/build/transaction/builders/UnwarpTransaction.js +0 -199
- package/build/transaction/interfaces/ITransactions.d.ts +0 -32
- package/build/transaction/interfaces/ITransactions.js +0 -1
- package/build/utxo/IUTXO.d.ts +0 -0
- package/build/utxo/IUTXO.js +0 -1
- package/build/utxo/OPNetUtils.d.ts +0 -7
- package/build/utxo/OPNetUtils.js +0 -47
- package/build/utxo/UTXOManager.d.ts +0 -7
- package/build/utxo/UTXOManager.js +0 -47
- package/build/wbtc/BroadcastResponse.d.ts +0 -0
- package/build/wbtc/BroadcastResponse.js +0 -1
- package/examples/Deploy.md +0 -188
- package/examples/Unwrap.md +0 -165
- package/examples/Wrap.md +0 -194
- package/tsconfig.cjs.json +0 -13
- /package/build/generators/{features.d.ts → Features.d.ts} +0 -0
- /package/build/generators/{features.js → Features.js} +0 -0
|
@@ -1,659 +1,659 @@
|
|
|
1
|
-
import { PsbtInput, TapScriptSig } from 'bip174/src/lib/interfaces.js';
|
|
2
|
-
import { crypto as bitcoinCrypto, opcodes, Payment, Psbt, script, Signer } from 'bitcoinjs-lib';
|
|
3
|
-
import { Taptree } from 'bitcoinjs-lib/src/types.js';
|
|
4
|
-
import { TransactionBuilder } from './TransactionBuilder.js';
|
|
5
|
-
import { TransactionType } from '../enums/TransactionType.js';
|
|
6
|
-
import { ITransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
7
|
-
import { MultiSignGenerator } from '../../generators/builders/MultiSignGenerator.js';
|
|
8
|
-
import { PsbtInputExtended, PsbtOutputExtended } from '../interfaces/Tap.js';
|
|
9
|
-
import { Address } from '@btc-vision/bsi-binary';
|
|
10
|
-
import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
11
|
-
import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
|
|
12
|
-
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
13
|
-
|
|
14
|
-
export interface MultiSignParameters
|
|
15
|
-
extends Omit<ITransactionParameters, 'priorityFee' | 'signer'> {
|
|
16
|
-
readonly pubkeys: Buffer[];
|
|
17
|
-
readonly minimumSignatures: number;
|
|
18
|
-
readonly from?: undefined;
|
|
19
|
-
readonly to?: undefined;
|
|
20
|
-
readonly psbt?: Psbt;
|
|
21
|
-
readonly receiver: Address;
|
|
22
|
-
readonly requestedAmount: bigint;
|
|
23
|
-
readonly refundVault: Address;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface MultiSignFromBase64Params extends Omit<MultiSignParameters, 'psbt'> {
|
|
27
|
-
readonly psbt: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Create a multi sign p2tr transaction
|
|
32
|
-
* @class MultiSignTransaction
|
|
33
|
-
*/
|
|
34
|
-
export class MultiSignTransaction extends TransactionBuilder<TransactionType.MULTI_SIG> {
|
|
35
|
-
public static readonly LOCK_LEAF_SCRIPT: Buffer = script.compile([
|
|
36
|
-
opcodes.OP_XOR,
|
|
37
|
-
opcodes.OP_NOP,
|
|
38
|
-
opcodes.OP_CODESEPARATOR,
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
public static readonly signHashTypesArray: number[] = [
|
|
42
|
-
//Transaction.SIGHASH_ALL,
|
|
43
|
-
//Transaction.SIGHASH_ANYONECANPAY,
|
|
44
|
-
];
|
|
45
|
-
public static readonly numsPoint = Buffer.from(
|
|
46
|
-
'50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0',
|
|
47
|
-
'hex',
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
public type: TransactionType.MULTI_SIG = TransactionType.MULTI_SIG;
|
|
51
|
-
|
|
52
|
-
protected targetScriptRedeem: Payment | null = null;
|
|
53
|
-
protected leftOverFundsScriptRedeem: Payment | null = null;
|
|
54
|
-
|
|
55
|
-
protected readonly compiledTargetScript: Buffer;
|
|
56
|
-
protected readonly scriptTree: Taptree;
|
|
57
|
-
|
|
58
|
-
protected readonly publicKeys: Buffer[];
|
|
59
|
-
protected readonly minimumSignatures: number;
|
|
60
|
-
|
|
61
|
-
protected readonly originalInputCount: number = 0;
|
|
62
|
-
protected readonly requestedAmount: bigint;
|
|
63
|
-
|
|
64
|
-
protected readonly receiver: Address;
|
|
65
|
-
protected readonly refundVault: Address;
|
|
66
|
-
/**
|
|
67
|
-
* @description Sign hash types
|
|
68
|
-
* @protected
|
|
69
|
-
*/
|
|
70
|
-
protected readonly sighashTypes: number[] = MultiSignTransaction.signHashTypesArray;
|
|
71
|
-
|
|
72
|
-
public constructor(parameters: MultiSignParameters) {
|
|
73
|
-
if (!parameters.refundVault) {
|
|
74
|
-
throw new Error('Refund vault is required');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!parameters.requestedAmount) {
|
|
78
|
-
throw new Error('Requested amount is required');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!parameters.receiver) {
|
|
82
|
-
throw new Error('Receiver is required');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
super({
|
|
86
|
-
...parameters,
|
|
87
|
-
signer: EcKeyPair.fromPrivateKey(
|
|
88
|
-
bitcoinCrypto.sha256(Buffer.from('aaaaaaaa', 'utf-8')),
|
|
89
|
-
),
|
|
90
|
-
priorityFee: 0n,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
if (!parameters.pubkeys) {
|
|
94
|
-
throw new Error('Pubkeys are required');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (parameters.psbt) {
|
|
98
|
-
this.log(`Using provided PSBT.`);
|
|
99
|
-
this.transaction = parameters.psbt;
|
|
100
|
-
|
|
101
|
-
this.originalInputCount = this.transaction.data.inputs.length;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
this.refundVault = parameters.refundVault;
|
|
105
|
-
this.requestedAmount = parameters.requestedAmount;
|
|
106
|
-
this.receiver = parameters.receiver;
|
|
107
|
-
|
|
108
|
-
this.publicKeys = parameters.pubkeys;
|
|
109
|
-
this.minimumSignatures = parameters.minimumSignatures;
|
|
110
|
-
|
|
111
|
-
this.compiledTargetScript = MultiSignGenerator.compile(
|
|
112
|
-
parameters.pubkeys,
|
|
113
|
-
this.minimumSignatures,
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
this.scriptTree = this.getScriptTree();
|
|
117
|
-
this.internalInit();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Generate a multisig transaction from a base64 psbt.
|
|
122
|
-
* @param {MultiSignFromBase64Params} params The parameters
|
|
123
|
-
* @returns {MultiSignTransaction} The multisig transaction
|
|
124
|
-
*/
|
|
125
|
-
public static fromBase64(params: MultiSignFromBase64Params): MultiSignTransaction {
|
|
126
|
-
const psbt = Psbt.fromBase64(params.psbt, { network: params.network });
|
|
127
|
-
return new MultiSignTransaction({
|
|
128
|
-
...params,
|
|
129
|
-
psbt,
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Verify if that public key already signed the transaction
|
|
135
|
-
* @param {Psbt} psbt The psbt
|
|
136
|
-
* @param {Buffer} signerPubKey The signer public key
|
|
137
|
-
* @returns {boolean} True if the public key signed the transaction
|
|
138
|
-
*/
|
|
139
|
-
public static verifyIfSigned(psbt: Psbt, signerPubKey: Buffer): boolean {
|
|
140
|
-
let alreadySigned: boolean = false;
|
|
141
|
-
for (let i = 1; i < psbt.data.inputs.length; i++) {
|
|
142
|
-
let input: PsbtInput = psbt.data.inputs[i];
|
|
143
|
-
if (!input.finalScriptWitness) {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const decoded = TransactionBuilder.readScriptWitnessToWitnessStack(
|
|
148
|
-
input.finalScriptWitness,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
if (decoded.length < 3) {
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
for (let j = 0; j < decoded.length - 2; j += 3) {
|
|
156
|
-
const pubKey = decoded[j + 2];
|
|
157
|
-
|
|
158
|
-
if (pubKey.equals(signerPubKey)) {
|
|
159
|
-
alreadySigned = true;
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return alreadySigned;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Partially sign the transaction
|
|
170
|
-
* @returns {boolean} True if the transaction was signed
|
|
171
|
-
* @public
|
|
172
|
-
*/
|
|
173
|
-
public static signPartial(
|
|
174
|
-
psbt: Psbt,
|
|
175
|
-
signer: Signer,
|
|
176
|
-
originalInputCount: number,
|
|
177
|
-
minimums: number[],
|
|
178
|
-
): {
|
|
179
|
-
final: boolean;
|
|
180
|
-
signed: boolean;
|
|
181
|
-
} {
|
|
182
|
-
let signed: boolean = false;
|
|
183
|
-
let final: boolean = true;
|
|
184
|
-
|
|
185
|
-
for (let i = originalInputCount; i < psbt.data.inputs.length; i++) {
|
|
186
|
-
let input: PsbtInput = psbt.data.inputs[i];
|
|
187
|
-
if (!input.tapInternalKey) {
|
|
188
|
-
input.tapInternalKey = toXOnly(MultiSignTransaction.numsPoint);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
let partialSignatures: TapScriptSig[] = [];
|
|
192
|
-
if (input.finalScriptWitness) {
|
|
193
|
-
const decoded = TransactionBuilder.readScriptWitnessToWitnessStack(
|
|
194
|
-
input.finalScriptWitness,
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
input.tapLeafScript = [
|
|
198
|
-
{
|
|
199
|
-
leafVersion: 192,
|
|
200
|
-
script: decoded[decoded.length - 2],
|
|
201
|
-
controlBlock: decoded[decoded.length - 1],
|
|
202
|
-
},
|
|
203
|
-
];
|
|
204
|
-
|
|
205
|
-
// we must insert all the partial signatures, decoded.length - 2
|
|
206
|
-
for (let j = 0; j < decoded.length - 2; j += 3) {
|
|
207
|
-
partialSignatures.push({
|
|
208
|
-
signature: decoded[j],
|
|
209
|
-
leafHash: decoded[j + 1],
|
|
210
|
-
pubkey: decoded[j + 2],
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
input.tapScriptSig = (input.tapScriptSig || []).concat(partialSignatures);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
delete input.finalScriptWitness;
|
|
218
|
-
|
|
219
|
-
const signHashTypes: number[] = MultiSignTransaction.signHashTypesArray
|
|
220
|
-
? [MultiSignTransaction.calculateSignHash(MultiSignTransaction.signHashTypesArray)]
|
|
221
|
-
: [];
|
|
222
|
-
|
|
223
|
-
try {
|
|
224
|
-
MultiSignTransaction.signInput(psbt, input, i, signer, signHashTypes);
|
|
225
|
-
|
|
226
|
-
signed = true;
|
|
227
|
-
} catch (e) {
|
|
228
|
-
console.log(e);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (signed) {
|
|
232
|
-
if (!input.tapScriptSig) throw new Error('No new signatures for input');
|
|
233
|
-
if (input.tapScriptSig.length !== minimums[i - originalInputCount]) {
|
|
234
|
-
final = false;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return {
|
|
240
|
-
signed,
|
|
241
|
-
final: !signed ? false : final,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Partially finalize a P2TR MS transaction
|
|
247
|
-
* @param {number} inputIndex The input index
|
|
248
|
-
* @param {PsbtInput} input The input
|
|
249
|
-
* @param {Buffer[]} partialSignatures The partial signatures
|
|
250
|
-
* @param {Buffer[]} orderedPubKeys The ordered public keys
|
|
251
|
-
* @param {boolean} isFinal If the transaction is final
|
|
252
|
-
*/
|
|
253
|
-
public static partialFinalizer = (
|
|
254
|
-
inputIndex: number,
|
|
255
|
-
input: PsbtInput,
|
|
256
|
-
partialSignatures: Buffer[],
|
|
257
|
-
orderedPubKeys: Buffer[],
|
|
258
|
-
isFinal: boolean,
|
|
259
|
-
) => {
|
|
260
|
-
if (
|
|
261
|
-
!input.tapLeafScript ||
|
|
262
|
-
!input.tapLeafScript[0].script ||
|
|
263
|
-
!input.tapLeafScript[0].controlBlock
|
|
264
|
-
) {
|
|
265
|
-
throw new Error('Tap leaf script is required');
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (!input.tapScriptSig) {
|
|
269
|
-
throw new Error(`No new signatures for input ${inputIndex}.`);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
let scriptSolution: Buffer[] = [];
|
|
273
|
-
if (!isFinal) {
|
|
274
|
-
scriptSolution = input.tapScriptSig
|
|
275
|
-
.map((sig) => {
|
|
276
|
-
return [sig.signature, sig.leafHash, sig.pubkey];
|
|
277
|
-
})
|
|
278
|
-
.flat();
|
|
279
|
-
} else {
|
|
280
|
-
/** We must order the signatures and the pub keys. */
|
|
281
|
-
for (let pubKey of orderedPubKeys) {
|
|
282
|
-
let found = false;
|
|
283
|
-
for (let sig of input.tapScriptSig) {
|
|
284
|
-
if (sig.pubkey.equals(toXOnly(pubKey))) {
|
|
285
|
-
scriptSolution.push(sig.signature);
|
|
286
|
-
found = true;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (!found) {
|
|
291
|
-
scriptSolution.push(Buffer.alloc(0));
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
scriptSolution = scriptSolution.reverse();
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (partialSignatures.length > 0) {
|
|
299
|
-
scriptSolution = scriptSolution.concat(partialSignatures);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const witness = scriptSolution
|
|
303
|
-
.concat(input.tapLeafScript[0].script)
|
|
304
|
-
.concat(input.tapLeafScript[0].controlBlock);
|
|
305
|
-
|
|
306
|
-
return {
|
|
307
|
-
finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
|
|
308
|
-
};
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Dedupe signatures
|
|
313
|
-
* @param {TapScriptSig[]} original The original signatures
|
|
314
|
-
* @param {TapScriptSig[]} partial The partial signatures
|
|
315
|
-
* @returns {TapScriptSig[]} The deduped signatures
|
|
316
|
-
*/
|
|
317
|
-
public static dedupeSignatures(
|
|
318
|
-
original: TapScriptSig[],
|
|
319
|
-
partial: TapScriptSig[],
|
|
320
|
-
): TapScriptSig[] {
|
|
321
|
-
const signatures = new Map<string, TapScriptSig>();
|
|
322
|
-
for (const sig of original) {
|
|
323
|
-
signatures.set(sig.pubkey.toString('hex'), sig);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
for (const sig of partial) {
|
|
327
|
-
if (!signatures.has(sig.pubkey.toString('hex'))) {
|
|
328
|
-
signatures.set(sig.pubkey.toString('hex'), sig);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return Array.from(signatures.values());
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Attempt to finalize the inputs
|
|
337
|
-
* @param {Psbt} psbt The psbt
|
|
338
|
-
* @param {number} startIndex The start index
|
|
339
|
-
* @param {Buffer[]} orderedPubKeys The ordered public keys
|
|
340
|
-
* @param {boolean} isFinal If the transaction is final
|
|
341
|
-
* @returns {boolean} True if the inputs were finalized
|
|
342
|
-
*/
|
|
343
|
-
public static attemptFinalizeInputs(
|
|
344
|
-
psbt: Psbt,
|
|
345
|
-
startIndex: number,
|
|
346
|
-
orderedPubKeys: Buffer[][],
|
|
347
|
-
isFinal: boolean,
|
|
348
|
-
): boolean {
|
|
349
|
-
let finalizedInputs = 0;
|
|
350
|
-
for (let i = startIndex; i < psbt.data.inputs.length; i++) {
|
|
351
|
-
try {
|
|
352
|
-
let input = psbt.data.inputs[i];
|
|
353
|
-
|
|
354
|
-
if (!input.tapInternalKey) {
|
|
355
|
-
input.tapInternalKey = toXOnly(MultiSignTransaction.numsPoint);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
let partialSignatures: TapScriptSig[] = [];
|
|
359
|
-
if (input.finalScriptWitness) {
|
|
360
|
-
const decoded = TransactionBuilder.readScriptWitnessToWitnessStack(
|
|
361
|
-
input.finalScriptWitness,
|
|
362
|
-
);
|
|
363
|
-
|
|
364
|
-
// we must insert all the partial signatures, decoded.length - 2
|
|
365
|
-
for (let j = 0; j < decoded.length - 2; j += 3) {
|
|
366
|
-
partialSignatures.push({
|
|
367
|
-
signature: decoded[j],
|
|
368
|
-
leafHash: decoded[j + 1],
|
|
369
|
-
pubkey: decoded[j + 2],
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
input.tapLeafScript = [
|
|
374
|
-
{
|
|
375
|
-
leafVersion: 192,
|
|
376
|
-
script: decoded[decoded.length - 2],
|
|
377
|
-
controlBlock: decoded[decoded.length - 1],
|
|
378
|
-
},
|
|
379
|
-
];
|
|
380
|
-
|
|
381
|
-
input.tapScriptSig = MultiSignTransaction.dedupeSignatures(
|
|
382
|
-
input.tapScriptSig || [],
|
|
383
|
-
partialSignatures,
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
delete input.finalScriptWitness;
|
|
388
|
-
|
|
389
|
-
psbt.finalizeInput(
|
|
390
|
-
i,
|
|
391
|
-
(
|
|
392
|
-
inputIndex: number,
|
|
393
|
-
input: PsbtInput,
|
|
394
|
-
): {
|
|
395
|
-
finalScriptWitness: Buffer | undefined;
|
|
396
|
-
} => {
|
|
397
|
-
return MultiSignTransaction.partialFinalizer(
|
|
398
|
-
inputIndex,
|
|
399
|
-
input,
|
|
400
|
-
[],
|
|
401
|
-
orderedPubKeys[i - startIndex],
|
|
402
|
-
isFinal,
|
|
403
|
-
);
|
|
404
|
-
},
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
finalizedInputs++;
|
|
408
|
-
} catch (e) {}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
return finalizedInputs === psbt.data.inputs.length - startIndex;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Finalize the psbt multisig transaction
|
|
416
|
-
*/
|
|
417
|
-
public finalizeTransactionInputs(): boolean {
|
|
418
|
-
let finalized: boolean = false;
|
|
419
|
-
try {
|
|
420
|
-
for (let i = this.originalInputCount; i < this.transaction.data.inputs.length; i++) {
|
|
421
|
-
this.transaction.finalizeInput(i, this.customFinalizer.bind(this));
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
finalized = true;
|
|
425
|
-
} catch (e) {
|
|
426
|
-
this.error(`Error finalizing transaction inputs: ${(e as Error).stack}`);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
return finalized;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* @description Signs the transaction
|
|
434
|
-
* @public
|
|
435
|
-
* @returns {Promise<Psbt>} - The signed transaction in hex format
|
|
436
|
-
* @throws {Error} - If something went wrong
|
|
437
|
-
*/
|
|
438
|
-
public async signPSBT(): Promise<Psbt> {
|
|
439
|
-
if (await this.signTransaction()) {
|
|
440
|
-
return this.transaction;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
throw new Error('Could not sign transaction');
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Build the transaction
|
|
448
|
-
* @protected
|
|
449
|
-
*
|
|
450
|
-
* @throws {Error} If the left over funds script redeem is required
|
|
451
|
-
* @throws {Error} If the left over funds script redeem version is required
|
|
452
|
-
* @throws {Error} If the left over funds script redeem output is required
|
|
453
|
-
*/
|
|
454
|
-
protected override async buildTransaction(): Promise<void> {
|
|
455
|
-
const selectedRedeem = this.targetScriptRedeem;
|
|
456
|
-
if (!selectedRedeem) {
|
|
457
|
-
throw new Error('Left over funds script redeem is required');
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
if (!selectedRedeem.redeemVersion) {
|
|
461
|
-
throw new Error('Left over funds script redeem version is required');
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (!selectedRedeem.output) {
|
|
465
|
-
throw new Error('Left over funds script redeem output is required');
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
this.tapLeafScript = {
|
|
469
|
-
leafVersion: selectedRedeem.redeemVersion,
|
|
470
|
-
script: selectedRedeem.output,
|
|
471
|
-
controlBlock: this.getWitness(),
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
this.addInputsFromUTXO();
|
|
475
|
-
|
|
476
|
-
const outputLeftAmount = this.calculateOutputLeftAmountFromVaults(this.utxos);
|
|
477
|
-
if (outputLeftAmount < 0) {
|
|
478
|
-
throw new Error(`Output value left is negative ${outputLeftAmount}.`);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
this.addOutput({
|
|
482
|
-
address: this.refundVault,
|
|
483
|
-
value: Number(outputLeftAmount),
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
this.addOutput({
|
|
487
|
-
address: this.receiver,
|
|
488
|
-
value: Number(this.requestedAmount),
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* Builds the transaction.
|
|
494
|
-
* @param {Psbt} transaction - The transaction to build
|
|
495
|
-
* @protected
|
|
496
|
-
* @returns {Promise<boolean>}
|
|
497
|
-
* @throws {Error} - If something went wrong while building the transaction
|
|
498
|
-
*/
|
|
499
|
-
protected override async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
|
|
500
|
-
const inputs: PsbtInputExtended[] = this.getInputs();
|
|
501
|
-
const outputs: PsbtOutputExtended[] = this.getOutputs();
|
|
502
|
-
|
|
503
|
-
transaction.setMaximumFeeRate(this._maximumFeeRate);
|
|
504
|
-
transaction.addInputs(inputs);
|
|
505
|
-
|
|
506
|
-
for (let i = 0; i < this.updateInputs.length; i++) {
|
|
507
|
-
transaction.updateInput(i, this.updateInputs[i]);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
transaction.addOutputs(outputs);
|
|
511
|
-
|
|
512
|
-
try {
|
|
513
|
-
await this.signInputs(transaction);
|
|
514
|
-
|
|
515
|
-
return this.finalizeTransactionInputs();
|
|
516
|
-
} catch (e) {
|
|
517
|
-
const err: Error = e as Error;
|
|
518
|
-
|
|
519
|
-
this.error(
|
|
520
|
-
`[internalBuildTransaction] Something went wrong while getting building the transaction: ${err.stack}`,
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Sign the inputs
|
|
529
|
-
* @protected
|
|
530
|
-
*/
|
|
531
|
-
protected override async signInputs(_transaction: Psbt): Promise<void> {}
|
|
532
|
-
|
|
533
|
-
protected override generateScriptAddress(): Payment {
|
|
534
|
-
return {
|
|
535
|
-
internalPubkey: toXOnly(MultiSignTransaction.numsPoint), //this.internalPubKeyToXOnly(),
|
|
536
|
-
network: this.network,
|
|
537
|
-
scriptTree: this.scriptTree,
|
|
538
|
-
//pubkeys: this.publicKeys,
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
protected override generateTapData(): Payment {
|
|
543
|
-
const selectedRedeem = this.targetScriptRedeem;
|
|
544
|
-
if (!selectedRedeem) {
|
|
545
|
-
throw new Error('Left over funds script redeem is required');
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
if (!this.scriptTree) {
|
|
549
|
-
throw new Error('Script tree is required');
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
return {
|
|
553
|
-
internalPubkey: toXOnly(MultiSignTransaction.numsPoint), //this.internalPubKeyToXOnly(),
|
|
554
|
-
network: this.network,
|
|
555
|
-
scriptTree: this.scriptTree,
|
|
556
|
-
redeem: selectedRedeem,
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
/**
|
|
561
|
-
* Generate the script solution
|
|
562
|
-
* @param {PsbtInput} input The input
|
|
563
|
-
* @protected
|
|
564
|
-
*
|
|
565
|
-
* @returns {Buffer[]} The script solution
|
|
566
|
-
*/
|
|
567
|
-
protected getScriptSolution(input: PsbtInput): Buffer[] {
|
|
568
|
-
if (!input.tapScriptSig) {
|
|
569
|
-
return [];
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
return input.tapScriptSig.map((sig) => {
|
|
573
|
-
return sig.signature;
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
* Get the script tree
|
|
579
|
-
* @private
|
|
580
|
-
*
|
|
581
|
-
* @returns {Taptree} The script tree
|
|
582
|
-
*/
|
|
583
|
-
protected getScriptTree(): Taptree {
|
|
584
|
-
this.generateRedeemScripts();
|
|
585
|
-
|
|
586
|
-
return [
|
|
587
|
-
{
|
|
588
|
-
output: this.compiledTargetScript,
|
|
589
|
-
version: 192,
|
|
590
|
-
},
|
|
591
|
-
{
|
|
592
|
-
output: MultiSignTransaction.LOCK_LEAF_SCRIPT,
|
|
593
|
-
version: 192,
|
|
594
|
-
},
|
|
595
|
-
];
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
private getTotalOutputAmount(utxos: UTXO[]): bigint {
|
|
599
|
-
let total = BigInt(0);
|
|
600
|
-
for (const utxo of utxos) {
|
|
601
|
-
total += BigInt(utxo.value);
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
return total;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
/**
|
|
608
|
-
* @description Calculate the amount left to refund to the first vault.
|
|
609
|
-
* @private
|
|
610
|
-
* @returns {bigint} The amount left
|
|
611
|
-
*/
|
|
612
|
-
private calculateOutputLeftAmountFromVaults(utxos: UTXO[]): bigint {
|
|
613
|
-
const total = this.getTotalOutputAmount(utxos);
|
|
614
|
-
|
|
615
|
-
return total - this.requestedAmount;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/**
|
|
619
|
-
* Transaction finalizer
|
|
620
|
-
* @param {number} _inputIndex The input index
|
|
621
|
-
* @param {PsbtInput} input The input
|
|
622
|
-
*/
|
|
623
|
-
private customFinalizer = (_inputIndex: number, input: PsbtInput) => {
|
|
624
|
-
if (!this.tapLeafScript) {
|
|
625
|
-
throw new Error('Tap leaf script is required');
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
const scriptSolution = this.getScriptSolution(input);
|
|
629
|
-
const witness = scriptSolution
|
|
630
|
-
.concat(this.tapLeafScript.script)
|
|
631
|
-
.concat(this.tapLeafScript.controlBlock);
|
|
632
|
-
|
|
633
|
-
return {
|
|
634
|
-
finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
|
|
635
|
-
};
|
|
636
|
-
};
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* Generate the redeem scripts
|
|
640
|
-
* @private
|
|
641
|
-
*
|
|
642
|
-
* @throws {Error} If the public keys are required
|
|
643
|
-
* @throws {Error} If the leaf script is required
|
|
644
|
-
* @throws {Error} If the leaf script version is required
|
|
645
|
-
* @throws {Error} If the leaf script output is required
|
|
646
|
-
* @throws {Error} If the target script redeem is required
|
|
647
|
-
*/
|
|
648
|
-
private generateRedeemScripts(): void {
|
|
649
|
-
this.targetScriptRedeem = {
|
|
650
|
-
output: this.compiledTargetScript,
|
|
651
|
-
redeemVersion: 192,
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
this.leftOverFundsScriptRedeem = {
|
|
655
|
-
output: MultiSignTransaction.LOCK_LEAF_SCRIPT,
|
|
656
|
-
redeemVersion: 192,
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
}
|
|
1
|
+
import { PsbtInput, TapScriptSig } from 'bip174/src/lib/interfaces.js';
|
|
2
|
+
import { crypto as bitcoinCrypto, opcodes, Payment, Psbt, script, Signer } from 'bitcoinjs-lib';
|
|
3
|
+
import { Taptree } from 'bitcoinjs-lib/src/types.js';
|
|
4
|
+
import { TransactionBuilder } from './TransactionBuilder.js';
|
|
5
|
+
import { TransactionType } from '../enums/TransactionType.js';
|
|
6
|
+
import { ITransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
7
|
+
import { MultiSignGenerator } from '../../generators/builders/MultiSignGenerator.js';
|
|
8
|
+
import { PsbtInputExtended, PsbtOutputExtended } from '../interfaces/Tap.js';
|
|
9
|
+
import { Address } from '@btc-vision/bsi-binary';
|
|
10
|
+
import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
11
|
+
import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
|
|
12
|
+
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
13
|
+
|
|
14
|
+
export interface MultiSignParameters
|
|
15
|
+
extends Omit<ITransactionParameters, 'priorityFee' | 'signer'> {
|
|
16
|
+
readonly pubkeys: Buffer[];
|
|
17
|
+
readonly minimumSignatures: number;
|
|
18
|
+
readonly from?: undefined;
|
|
19
|
+
readonly to?: undefined;
|
|
20
|
+
readonly psbt?: Psbt;
|
|
21
|
+
readonly receiver: Address;
|
|
22
|
+
readonly requestedAmount: bigint;
|
|
23
|
+
readonly refundVault: Address;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface MultiSignFromBase64Params extends Omit<MultiSignParameters, 'psbt'> {
|
|
27
|
+
readonly psbt: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a multi sign p2tr transaction
|
|
32
|
+
* @class MultiSignTransaction
|
|
33
|
+
*/
|
|
34
|
+
export class MultiSignTransaction extends TransactionBuilder<TransactionType.MULTI_SIG> {
|
|
35
|
+
public static readonly LOCK_LEAF_SCRIPT: Buffer = script.compile([
|
|
36
|
+
opcodes.OP_XOR,
|
|
37
|
+
opcodes.OP_NOP,
|
|
38
|
+
opcodes.OP_CODESEPARATOR,
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
public static readonly signHashTypesArray: number[] = [
|
|
42
|
+
//Transaction.SIGHASH_ALL,
|
|
43
|
+
//Transaction.SIGHASH_ANYONECANPAY,
|
|
44
|
+
];
|
|
45
|
+
public static readonly numsPoint = Buffer.from(
|
|
46
|
+
'50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0',
|
|
47
|
+
'hex',
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
public type: TransactionType.MULTI_SIG = TransactionType.MULTI_SIG;
|
|
51
|
+
|
|
52
|
+
protected targetScriptRedeem: Payment | null = null;
|
|
53
|
+
protected leftOverFundsScriptRedeem: Payment | null = null;
|
|
54
|
+
|
|
55
|
+
protected readonly compiledTargetScript: Buffer;
|
|
56
|
+
protected readonly scriptTree: Taptree;
|
|
57
|
+
|
|
58
|
+
protected readonly publicKeys: Buffer[];
|
|
59
|
+
protected readonly minimumSignatures: number;
|
|
60
|
+
|
|
61
|
+
protected readonly originalInputCount: number = 0;
|
|
62
|
+
protected readonly requestedAmount: bigint;
|
|
63
|
+
|
|
64
|
+
protected readonly receiver: Address;
|
|
65
|
+
protected readonly refundVault: Address;
|
|
66
|
+
/**
|
|
67
|
+
* @description Sign hash types
|
|
68
|
+
* @protected
|
|
69
|
+
*/
|
|
70
|
+
protected readonly sighashTypes: number[] = MultiSignTransaction.signHashTypesArray;
|
|
71
|
+
|
|
72
|
+
public constructor(parameters: MultiSignParameters) {
|
|
73
|
+
if (!parameters.refundVault) {
|
|
74
|
+
throw new Error('Refund vault is required');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!parameters.requestedAmount) {
|
|
78
|
+
throw new Error('Requested amount is required');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!parameters.receiver) {
|
|
82
|
+
throw new Error('Receiver is required');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
super({
|
|
86
|
+
...parameters,
|
|
87
|
+
signer: EcKeyPair.fromPrivateKey(
|
|
88
|
+
bitcoinCrypto.sha256(Buffer.from('aaaaaaaa', 'utf-8')),
|
|
89
|
+
),
|
|
90
|
+
priorityFee: 0n,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (!parameters.pubkeys) {
|
|
94
|
+
throw new Error('Pubkeys are required');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (parameters.psbt) {
|
|
98
|
+
this.log(`Using provided PSBT.`);
|
|
99
|
+
this.transaction = parameters.psbt;
|
|
100
|
+
|
|
101
|
+
this.originalInputCount = this.transaction.data.inputs.length;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.refundVault = parameters.refundVault;
|
|
105
|
+
this.requestedAmount = parameters.requestedAmount;
|
|
106
|
+
this.receiver = parameters.receiver;
|
|
107
|
+
|
|
108
|
+
this.publicKeys = parameters.pubkeys;
|
|
109
|
+
this.minimumSignatures = parameters.minimumSignatures;
|
|
110
|
+
|
|
111
|
+
this.compiledTargetScript = MultiSignGenerator.compile(
|
|
112
|
+
parameters.pubkeys,
|
|
113
|
+
this.minimumSignatures,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
this.scriptTree = this.getScriptTree();
|
|
117
|
+
this.internalInit();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Generate a multisig transaction from a base64 psbt.
|
|
122
|
+
* @param {MultiSignFromBase64Params} params The parameters
|
|
123
|
+
* @returns {MultiSignTransaction} The multisig transaction
|
|
124
|
+
*/
|
|
125
|
+
public static fromBase64(params: MultiSignFromBase64Params): MultiSignTransaction {
|
|
126
|
+
const psbt = Psbt.fromBase64(params.psbt, { network: params.network });
|
|
127
|
+
return new MultiSignTransaction({
|
|
128
|
+
...params,
|
|
129
|
+
psbt,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Verify if that public key already signed the transaction
|
|
135
|
+
* @param {Psbt} psbt The psbt
|
|
136
|
+
* @param {Buffer} signerPubKey The signer public key
|
|
137
|
+
* @returns {boolean} True if the public key signed the transaction
|
|
138
|
+
*/
|
|
139
|
+
public static verifyIfSigned(psbt: Psbt, signerPubKey: Buffer): boolean {
|
|
140
|
+
let alreadySigned: boolean = false;
|
|
141
|
+
for (let i = 1; i < psbt.data.inputs.length; i++) {
|
|
142
|
+
let input: PsbtInput = psbt.data.inputs[i];
|
|
143
|
+
if (!input.finalScriptWitness) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const decoded = TransactionBuilder.readScriptWitnessToWitnessStack(
|
|
148
|
+
input.finalScriptWitness,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
if (decoded.length < 3) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (let j = 0; j < decoded.length - 2; j += 3) {
|
|
156
|
+
const pubKey = decoded[j + 2];
|
|
157
|
+
|
|
158
|
+
if (pubKey.equals(signerPubKey)) {
|
|
159
|
+
alreadySigned = true;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return alreadySigned;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Partially sign the transaction
|
|
170
|
+
* @returns {boolean} True if the transaction was signed
|
|
171
|
+
* @public
|
|
172
|
+
*/
|
|
173
|
+
public static signPartial(
|
|
174
|
+
psbt: Psbt,
|
|
175
|
+
signer: Signer,
|
|
176
|
+
originalInputCount: number,
|
|
177
|
+
minimums: number[],
|
|
178
|
+
): {
|
|
179
|
+
final: boolean;
|
|
180
|
+
signed: boolean;
|
|
181
|
+
} {
|
|
182
|
+
let signed: boolean = false;
|
|
183
|
+
let final: boolean = true;
|
|
184
|
+
|
|
185
|
+
for (let i = originalInputCount; i < psbt.data.inputs.length; i++) {
|
|
186
|
+
let input: PsbtInput = psbt.data.inputs[i];
|
|
187
|
+
if (!input.tapInternalKey) {
|
|
188
|
+
input.tapInternalKey = toXOnly(MultiSignTransaction.numsPoint);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let partialSignatures: TapScriptSig[] = [];
|
|
192
|
+
if (input.finalScriptWitness) {
|
|
193
|
+
const decoded = TransactionBuilder.readScriptWitnessToWitnessStack(
|
|
194
|
+
input.finalScriptWitness,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
input.tapLeafScript = [
|
|
198
|
+
{
|
|
199
|
+
leafVersion: 192,
|
|
200
|
+
script: decoded[decoded.length - 2],
|
|
201
|
+
controlBlock: decoded[decoded.length - 1],
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
// we must insert all the partial signatures, decoded.length - 2
|
|
206
|
+
for (let j = 0; j < decoded.length - 2; j += 3) {
|
|
207
|
+
partialSignatures.push({
|
|
208
|
+
signature: decoded[j],
|
|
209
|
+
leafHash: decoded[j + 1],
|
|
210
|
+
pubkey: decoded[j + 2],
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
input.tapScriptSig = (input.tapScriptSig || []).concat(partialSignatures);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
delete input.finalScriptWitness;
|
|
218
|
+
|
|
219
|
+
const signHashTypes: number[] = MultiSignTransaction.signHashTypesArray
|
|
220
|
+
? [MultiSignTransaction.calculateSignHash(MultiSignTransaction.signHashTypesArray)]
|
|
221
|
+
: [];
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
MultiSignTransaction.signInput(psbt, input, i, signer, signHashTypes);
|
|
225
|
+
|
|
226
|
+
signed = true;
|
|
227
|
+
} catch (e) {
|
|
228
|
+
console.log(e);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (signed) {
|
|
232
|
+
if (!input.tapScriptSig) throw new Error('No new signatures for input');
|
|
233
|
+
if (input.tapScriptSig.length !== minimums[i - originalInputCount]) {
|
|
234
|
+
final = false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
signed,
|
|
241
|
+
final: !signed ? false : final,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Partially finalize a P2TR MS transaction
|
|
247
|
+
* @param {number} inputIndex The input index
|
|
248
|
+
* @param {PsbtInput} input The input
|
|
249
|
+
* @param {Buffer[]} partialSignatures The partial signatures
|
|
250
|
+
* @param {Buffer[]} orderedPubKeys The ordered public keys
|
|
251
|
+
* @param {boolean} isFinal If the transaction is final
|
|
252
|
+
*/
|
|
253
|
+
public static partialFinalizer = (
|
|
254
|
+
inputIndex: number,
|
|
255
|
+
input: PsbtInput,
|
|
256
|
+
partialSignatures: Buffer[],
|
|
257
|
+
orderedPubKeys: Buffer[],
|
|
258
|
+
isFinal: boolean,
|
|
259
|
+
) => {
|
|
260
|
+
if (
|
|
261
|
+
!input.tapLeafScript ||
|
|
262
|
+
!input.tapLeafScript[0].script ||
|
|
263
|
+
!input.tapLeafScript[0].controlBlock
|
|
264
|
+
) {
|
|
265
|
+
throw new Error('Tap leaf script is required');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (!input.tapScriptSig) {
|
|
269
|
+
throw new Error(`No new signatures for input ${inputIndex}.`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
let scriptSolution: Buffer[] = [];
|
|
273
|
+
if (!isFinal) {
|
|
274
|
+
scriptSolution = input.tapScriptSig
|
|
275
|
+
.map((sig) => {
|
|
276
|
+
return [sig.signature, sig.leafHash, sig.pubkey];
|
|
277
|
+
})
|
|
278
|
+
.flat();
|
|
279
|
+
} else {
|
|
280
|
+
/** We must order the signatures and the pub keys. */
|
|
281
|
+
for (let pubKey of orderedPubKeys) {
|
|
282
|
+
let found = false;
|
|
283
|
+
for (let sig of input.tapScriptSig) {
|
|
284
|
+
if (sig.pubkey.equals(toXOnly(pubKey))) {
|
|
285
|
+
scriptSolution.push(sig.signature);
|
|
286
|
+
found = true;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (!found) {
|
|
291
|
+
scriptSolution.push(Buffer.alloc(0));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
scriptSolution = scriptSolution.reverse();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (partialSignatures.length > 0) {
|
|
299
|
+
scriptSolution = scriptSolution.concat(partialSignatures);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const witness = scriptSolution
|
|
303
|
+
.concat(input.tapLeafScript[0].script)
|
|
304
|
+
.concat(input.tapLeafScript[0].controlBlock);
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Dedupe signatures
|
|
313
|
+
* @param {TapScriptSig[]} original The original signatures
|
|
314
|
+
* @param {TapScriptSig[]} partial The partial signatures
|
|
315
|
+
* @returns {TapScriptSig[]} The deduped signatures
|
|
316
|
+
*/
|
|
317
|
+
public static dedupeSignatures(
|
|
318
|
+
original: TapScriptSig[],
|
|
319
|
+
partial: TapScriptSig[],
|
|
320
|
+
): TapScriptSig[] {
|
|
321
|
+
const signatures = new Map<string, TapScriptSig>();
|
|
322
|
+
for (const sig of original) {
|
|
323
|
+
signatures.set(sig.pubkey.toString('hex'), sig);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
for (const sig of partial) {
|
|
327
|
+
if (!signatures.has(sig.pubkey.toString('hex'))) {
|
|
328
|
+
signatures.set(sig.pubkey.toString('hex'), sig);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return Array.from(signatures.values());
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Attempt to finalize the inputs
|
|
337
|
+
* @param {Psbt} psbt The psbt
|
|
338
|
+
* @param {number} startIndex The start index
|
|
339
|
+
* @param {Buffer[]} orderedPubKeys The ordered public keys
|
|
340
|
+
* @param {boolean} isFinal If the transaction is final
|
|
341
|
+
* @returns {boolean} True if the inputs were finalized
|
|
342
|
+
*/
|
|
343
|
+
public static attemptFinalizeInputs(
|
|
344
|
+
psbt: Psbt,
|
|
345
|
+
startIndex: number,
|
|
346
|
+
orderedPubKeys: Buffer[][],
|
|
347
|
+
isFinal: boolean,
|
|
348
|
+
): boolean {
|
|
349
|
+
let finalizedInputs = 0;
|
|
350
|
+
for (let i = startIndex; i < psbt.data.inputs.length; i++) {
|
|
351
|
+
try {
|
|
352
|
+
let input = psbt.data.inputs[i];
|
|
353
|
+
|
|
354
|
+
if (!input.tapInternalKey) {
|
|
355
|
+
input.tapInternalKey = toXOnly(MultiSignTransaction.numsPoint);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
let partialSignatures: TapScriptSig[] = [];
|
|
359
|
+
if (input.finalScriptWitness) {
|
|
360
|
+
const decoded = TransactionBuilder.readScriptWitnessToWitnessStack(
|
|
361
|
+
input.finalScriptWitness,
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// we must insert all the partial signatures, decoded.length - 2
|
|
365
|
+
for (let j = 0; j < decoded.length - 2; j += 3) {
|
|
366
|
+
partialSignatures.push({
|
|
367
|
+
signature: decoded[j],
|
|
368
|
+
leafHash: decoded[j + 1],
|
|
369
|
+
pubkey: decoded[j + 2],
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
input.tapLeafScript = [
|
|
374
|
+
{
|
|
375
|
+
leafVersion: 192,
|
|
376
|
+
script: decoded[decoded.length - 2],
|
|
377
|
+
controlBlock: decoded[decoded.length - 1],
|
|
378
|
+
},
|
|
379
|
+
];
|
|
380
|
+
|
|
381
|
+
input.tapScriptSig = MultiSignTransaction.dedupeSignatures(
|
|
382
|
+
input.tapScriptSig || [],
|
|
383
|
+
partialSignatures,
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
delete input.finalScriptWitness;
|
|
388
|
+
|
|
389
|
+
psbt.finalizeInput(
|
|
390
|
+
i,
|
|
391
|
+
(
|
|
392
|
+
inputIndex: number,
|
|
393
|
+
input: PsbtInput,
|
|
394
|
+
): {
|
|
395
|
+
finalScriptWitness: Buffer | undefined;
|
|
396
|
+
} => {
|
|
397
|
+
return MultiSignTransaction.partialFinalizer(
|
|
398
|
+
inputIndex,
|
|
399
|
+
input,
|
|
400
|
+
[],
|
|
401
|
+
orderedPubKeys[i - startIndex],
|
|
402
|
+
isFinal,
|
|
403
|
+
);
|
|
404
|
+
},
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
finalizedInputs++;
|
|
408
|
+
} catch (e) {}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return finalizedInputs === psbt.data.inputs.length - startIndex;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Finalize the psbt multisig transaction
|
|
416
|
+
*/
|
|
417
|
+
public finalizeTransactionInputs(): boolean {
|
|
418
|
+
let finalized: boolean = false;
|
|
419
|
+
try {
|
|
420
|
+
for (let i = this.originalInputCount; i < this.transaction.data.inputs.length; i++) {
|
|
421
|
+
this.transaction.finalizeInput(i, this.customFinalizer.bind(this));
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
finalized = true;
|
|
425
|
+
} catch (e) {
|
|
426
|
+
this.error(`Error finalizing transaction inputs: ${(e as Error).stack}`);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return finalized;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @description Signs the transaction
|
|
434
|
+
* @public
|
|
435
|
+
* @returns {Promise<Psbt>} - The signed transaction in hex format
|
|
436
|
+
* @throws {Error} - If something went wrong
|
|
437
|
+
*/
|
|
438
|
+
public async signPSBT(): Promise<Psbt> {
|
|
439
|
+
if (await this.signTransaction()) {
|
|
440
|
+
return this.transaction;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
throw new Error('Could not sign transaction');
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Build the transaction
|
|
448
|
+
* @protected
|
|
449
|
+
*
|
|
450
|
+
* @throws {Error} If the left over funds script redeem is required
|
|
451
|
+
* @throws {Error} If the left over funds script redeem version is required
|
|
452
|
+
* @throws {Error} If the left over funds script redeem output is required
|
|
453
|
+
*/
|
|
454
|
+
protected override async buildTransaction(): Promise<void> {
|
|
455
|
+
const selectedRedeem = this.targetScriptRedeem;
|
|
456
|
+
if (!selectedRedeem) {
|
|
457
|
+
throw new Error('Left over funds script redeem is required');
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!selectedRedeem.redeemVersion) {
|
|
461
|
+
throw new Error('Left over funds script redeem version is required');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (!selectedRedeem.output) {
|
|
465
|
+
throw new Error('Left over funds script redeem output is required');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
this.tapLeafScript = {
|
|
469
|
+
leafVersion: selectedRedeem.redeemVersion,
|
|
470
|
+
script: selectedRedeem.output,
|
|
471
|
+
controlBlock: this.getWitness(),
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
this.addInputsFromUTXO();
|
|
475
|
+
|
|
476
|
+
const outputLeftAmount = this.calculateOutputLeftAmountFromVaults(this.utxos);
|
|
477
|
+
if (outputLeftAmount < 0) {
|
|
478
|
+
throw new Error(`Output value left is negative ${outputLeftAmount}.`);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
this.addOutput({
|
|
482
|
+
address: this.refundVault,
|
|
483
|
+
value: Number(outputLeftAmount),
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
this.addOutput({
|
|
487
|
+
address: this.receiver,
|
|
488
|
+
value: Number(this.requestedAmount),
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Builds the transaction.
|
|
494
|
+
* @param {Psbt} transaction - The transaction to build
|
|
495
|
+
* @protected
|
|
496
|
+
* @returns {Promise<boolean>}
|
|
497
|
+
* @throws {Error} - If something went wrong while building the transaction
|
|
498
|
+
*/
|
|
499
|
+
protected override async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
|
|
500
|
+
const inputs: PsbtInputExtended[] = this.getInputs();
|
|
501
|
+
const outputs: PsbtOutputExtended[] = this.getOutputs();
|
|
502
|
+
|
|
503
|
+
transaction.setMaximumFeeRate(this._maximumFeeRate);
|
|
504
|
+
transaction.addInputs(inputs);
|
|
505
|
+
|
|
506
|
+
for (let i = 0; i < this.updateInputs.length; i++) {
|
|
507
|
+
transaction.updateInput(i, this.updateInputs[i]);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
transaction.addOutputs(outputs);
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
await this.signInputs(transaction);
|
|
514
|
+
|
|
515
|
+
return this.finalizeTransactionInputs();
|
|
516
|
+
} catch (e) {
|
|
517
|
+
const err: Error = e as Error;
|
|
518
|
+
|
|
519
|
+
this.error(
|
|
520
|
+
`[internalBuildTransaction] Something went wrong while getting building the transaction: ${err.stack}`,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Sign the inputs
|
|
529
|
+
* @protected
|
|
530
|
+
*/
|
|
531
|
+
protected override async signInputs(_transaction: Psbt): Promise<void> {}
|
|
532
|
+
|
|
533
|
+
protected override generateScriptAddress(): Payment {
|
|
534
|
+
return {
|
|
535
|
+
internalPubkey: toXOnly(MultiSignTransaction.numsPoint), //this.internalPubKeyToXOnly(),
|
|
536
|
+
network: this.network,
|
|
537
|
+
scriptTree: this.scriptTree,
|
|
538
|
+
//pubkeys: this.publicKeys,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
protected override generateTapData(): Payment {
|
|
543
|
+
const selectedRedeem = this.targetScriptRedeem;
|
|
544
|
+
if (!selectedRedeem) {
|
|
545
|
+
throw new Error('Left over funds script redeem is required');
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (!this.scriptTree) {
|
|
549
|
+
throw new Error('Script tree is required');
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return {
|
|
553
|
+
internalPubkey: toXOnly(MultiSignTransaction.numsPoint), //this.internalPubKeyToXOnly(),
|
|
554
|
+
network: this.network,
|
|
555
|
+
scriptTree: this.scriptTree,
|
|
556
|
+
redeem: selectedRedeem,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Generate the script solution
|
|
562
|
+
* @param {PsbtInput} input The input
|
|
563
|
+
* @protected
|
|
564
|
+
*
|
|
565
|
+
* @returns {Buffer[]} The script solution
|
|
566
|
+
*/
|
|
567
|
+
protected getScriptSolution(input: PsbtInput): Buffer[] {
|
|
568
|
+
if (!input.tapScriptSig) {
|
|
569
|
+
return [];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return input.tapScriptSig.map((sig) => {
|
|
573
|
+
return sig.signature;
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Get the script tree
|
|
579
|
+
* @private
|
|
580
|
+
*
|
|
581
|
+
* @returns {Taptree} The script tree
|
|
582
|
+
*/
|
|
583
|
+
protected getScriptTree(): Taptree {
|
|
584
|
+
this.generateRedeemScripts();
|
|
585
|
+
|
|
586
|
+
return [
|
|
587
|
+
{
|
|
588
|
+
output: this.compiledTargetScript,
|
|
589
|
+
version: 192,
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
output: MultiSignTransaction.LOCK_LEAF_SCRIPT,
|
|
593
|
+
version: 192,
|
|
594
|
+
},
|
|
595
|
+
];
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
private getTotalOutputAmount(utxos: UTXO[]): bigint {
|
|
599
|
+
let total = BigInt(0);
|
|
600
|
+
for (const utxo of utxos) {
|
|
601
|
+
total += BigInt(utxo.value);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return total;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* @description Calculate the amount left to refund to the first vault.
|
|
609
|
+
* @private
|
|
610
|
+
* @returns {bigint} The amount left
|
|
611
|
+
*/
|
|
612
|
+
private calculateOutputLeftAmountFromVaults(utxos: UTXO[]): bigint {
|
|
613
|
+
const total = this.getTotalOutputAmount(utxos);
|
|
614
|
+
|
|
615
|
+
return total - this.requestedAmount;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Transaction finalizer
|
|
620
|
+
* @param {number} _inputIndex The input index
|
|
621
|
+
* @param {PsbtInput} input The input
|
|
622
|
+
*/
|
|
623
|
+
private customFinalizer = (_inputIndex: number, input: PsbtInput) => {
|
|
624
|
+
if (!this.tapLeafScript) {
|
|
625
|
+
throw new Error('Tap leaf script is required');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const scriptSolution = this.getScriptSolution(input);
|
|
629
|
+
const witness = scriptSolution
|
|
630
|
+
.concat(this.tapLeafScript.script)
|
|
631
|
+
.concat(this.tapLeafScript.controlBlock);
|
|
632
|
+
|
|
633
|
+
return {
|
|
634
|
+
finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
|
|
635
|
+
};
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Generate the redeem scripts
|
|
640
|
+
* @private
|
|
641
|
+
*
|
|
642
|
+
* @throws {Error} If the public keys are required
|
|
643
|
+
* @throws {Error} If the leaf script is required
|
|
644
|
+
* @throws {Error} If the leaf script version is required
|
|
645
|
+
* @throws {Error} If the leaf script output is required
|
|
646
|
+
* @throws {Error} If the target script redeem is required
|
|
647
|
+
*/
|
|
648
|
+
private generateRedeemScripts(): void {
|
|
649
|
+
this.targetScriptRedeem = {
|
|
650
|
+
output: this.compiledTargetScript,
|
|
651
|
+
redeemVersion: 192,
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
this.leftOverFundsScriptRedeem = {
|
|
655
|
+
output: MultiSignTransaction.LOCK_LEAF_SCRIPT,
|
|
656
|
+
redeemVersion: 192,
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
}
|