@bitgo-beta/babylonlabs-io-btc-staking-ts 0.4.0-beta.74 → 0.4.0-beta.740

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/error/index.ts", "../src/utils/btc.ts", "../src/constants/keys.ts", "../src/utils/staking/index.ts", "../src/constants/internalPubkey.ts", "../src/staking/psbt.ts", "../src/constants/transaction.ts", "../src/utils/utxo/findInputUTXO.ts", "../src/utils/utxo/getScriptType.ts", "../src/utils/utxo/getPsbtInputFields.ts", "../src/staking/stakingScript.ts", "../src/staking/transactions.ts", "../src/constants/dustSat.ts", "../src/utils/fee/index.ts", "../src/constants/fee.ts", "../src/utils/fee/utils.ts", "../src/constants/psbt.ts", "../src/constants/unbonding.ts", "../src/utils/babylon.ts", "../src/utils/staking/validation.ts", "../src/staking/index.ts", "../src/staking/manager.ts", "../src/constants/registry.ts", "../src/utils/index.ts", "../src/utils/pop.ts", "../src/constants/staking.ts", "../src/utils/staking/param.ts", "../src/staking/observable/observableStakingScript.ts", "../src/staking/observable/index.ts", "../src/types/params.ts"],
4
+ "sourcesContent": ["export enum StakingErrorCode {\n UNKNOWN_ERROR = \"UNKNOWN_ERROR\",\n INVALID_INPUT = \"INVALID_INPUT\",\n INVALID_OUTPUT = \"INVALID_OUTPUT\",\n SCRIPT_FAILURE = \"SCRIPT_FAILURE\",\n BUILD_TRANSACTION_FAILURE = \"BUILD_TRANSACTION_FAILURE\",\n INVALID_PARAMS = \"INVALID_PARAMS\",\n}\n\nexport class StakingError extends Error {\n public code: StakingErrorCode;\n constructor(code: StakingErrorCode, message?: string) {\n super(message);\n this.code = code;\n }\n\n // Static method to safely handle unknown errors\n static fromUnknown(\n error: unknown, code: StakingErrorCode, fallbackMsg?: string\n ): StakingError {\n if (error instanceof StakingError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new StakingError(code, error.message);\n }\n return new StakingError(code, fallbackMsg);\n }\n}", "import * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { address, initEccLib, networks } from \"bitcoinjs-lib\";\nimport { NO_COORD_PK_BYTE_LENGTH } from \"../constants/keys\";\n\n// Initialize elliptic curve library\nexport const initBTCCurve = () => {\n initEccLib(ecc);\n};\n\n/**\n * Check whether the given address is a valid Bitcoin address.\n *\n * @param {string} btcAddress - The Bitcoin address to check.\n * @param {object} network - The Bitcoin network (e.g., bitcoin.networks.bitcoin).\n * @returns {boolean} - True if the address is valid, otherwise false.\n */\nexport const isValidBitcoinAddress = (\n btcAddress: string,\n network: networks.Network,\n): boolean => {\n try {\n return !!address.toOutputScript(btcAddress, network);\n } catch (error) {\n return false;\n }\n};\n\n/**\n * Check whether the given address is a Taproot address.\n *\n * @param {string} taprootAddress - The Bitcoin bech32 encoded address to check.\n * @param {object} network - The Bitcoin network (e.g., bitcoin.networks.bitcoin).\n * @returns {boolean} - True if the address is a Taproot address, otherwise false.\n */\nexport const isTaproot = (\n taprootAddress: string,\n network: networks.Network,\n): boolean => {\n try {\n const decoded = address.fromBech32(taprootAddress);\n if (decoded.version !== 1) {\n return false;\n }\n\n // Compare network properties instead of object reference\n // The bech32 is hardcoded in the bitcoinjs-lib library.\n // https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/networks.ts#L36\n if (network.bech32 === networks.bitcoin.bech32) {\n // Check if address starts with \"bc1p\"\n return taprootAddress.startsWith(\"bc1p\");\n } else if (network.bech32 === networks.testnet.bech32) {\n // signet, regtest and testnet taproot addresses start with \"tb1p\" or \"sb1p\"\n return (\n taprootAddress.startsWith(\"tb1p\") || taprootAddress.startsWith(\"sb1p\")\n );\n }\n return false;\n } catch (error) {\n return false;\n }\n};\n\n/**\n * Check whether the given address is a Native SegWit address.\n *\n * @param {string} segwitAddress - The Bitcoin bech32 encoded address to check.\n * @param {object} network - The Bitcoin network (e.g., bitcoin.networks.bitcoin).\n * @returns {boolean} - True if the address is a Native SegWit address, otherwise false.\n */\nexport const isNativeSegwit = (\n segwitAddress: string,\n network: networks.Network,\n): boolean => {\n try {\n const decoded = address.fromBech32(segwitAddress);\n if (decoded.version !== 0) {\n return false;\n }\n\n // Compare network properties instead of object reference\n // The bech32 is hardcoded in the bitcoinjs-lib library.\n // https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/networks.ts#L36\n if (network.bech32 === networks.bitcoin.bech32) {\n // Check if address starts with \"bc1q\"\n return segwitAddress.startsWith(\"bc1q\");\n } else if (network.bech32 === networks.testnet.bech32) {\n // testnet native segwit addresses start with \"tb1q\"\n return segwitAddress.startsWith(\"tb1q\");\n }\n return false;\n } catch (error) {\n return false;\n }\n};\n\n/**\n * Check whether the given public key is a valid public key without a coordinate.\n *\n * @param {string} pkWithNoCoord - public key without the coordinate.\n * @returns {boolean} - True if the public key without the coordinate is valid, otherwise false.\n */\nexport const isValidNoCoordPublicKey = (pkWithNoCoord: string): boolean => {\n try {\n const keyBuffer = Buffer.from(pkWithNoCoord, \"hex\");\n return validateNoCoordPublicKeyBuffer(keyBuffer);\n } catch (error) {\n return false;\n }\n};\n\n/**\n * Get the public key without the coordinate.\n *\n * @param {string} pkHex - The public key in hex, with or without the coordinate.\n * @returns {string} - The public key without the coordinate in hex.\n * @throws {Error} - If the public key is invalid.\n */\nexport const getPublicKeyNoCoord = (pkHex: string): string => {\n const publicKey = Buffer.from(pkHex, \"hex\");\n\n const publicKeyNoCoordBuffer =\n publicKey.length === NO_COORD_PK_BYTE_LENGTH\n ? publicKey\n : publicKey.subarray(1, 33);\n\n // Validate the public key without coordinate\n if (!validateNoCoordPublicKeyBuffer(publicKeyNoCoordBuffer)) {\n throw new Error(\"Invalid public key without coordinate\");\n }\n\n return publicKeyNoCoordBuffer.toString(\"hex\");\n};\n\nconst validateNoCoordPublicKeyBuffer = (pkBuffer: Buffer): boolean => {\n if (pkBuffer.length !== NO_COORD_PK_BYTE_LENGTH) {\n return false;\n }\n\n // Try both compressed forms: y-coordinate even (0x02) and y-coordinate odd (0x03)\n const compressedKeyEven = Buffer.concat([Buffer.from([0x02]), pkBuffer]);\n const compressedKeyOdd = Buffer.concat([Buffer.from([0x03]), pkBuffer]);\n\n return ecc.isPoint(compressedKeyEven) || ecc.isPoint(compressedKeyOdd);\n};\n\n/**\n * Convert a transaction id to a hash. in buffer format.\n *\n * @param {string} txId - The transaction id.\n * @returns {Buffer} - The transaction hash.\n */\nexport const transactionIdToHash = (txId: string): Buffer => {\n if (txId === \"\") {\n throw new Error(\"Transaction id cannot be empty\");\n }\n return Buffer.from(txId, \"hex\").reverse();\n};\n", "// NO_COORD_PK_BYTE_LENGTH is the length of a BTC public key without the coordinate in bytes.\nexport const NO_COORD_PK_BYTE_LENGTH = 32;", "import { address, networks, payments, Transaction } from \"bitcoinjs-lib\";\nimport { Taptree } from \"bitcoinjs-lib/src/types\";\nimport { internalPubkey } from \"../../constants/internalPubkey\";\nimport { StakingError, StakingErrorCode } from \"../../error\";\nimport { TransactionOutput } from \"../../types/psbtOutputs\";\nexport interface OutputInfo {\n scriptPubKey: Buffer;\n outputAddress: string;\n}\n\n/**\n * Build the staking output for the transaction which contains p2tr output\n * with staking scripts.\n *\n * @param {StakingScripts} scripts - The staking scripts.\n * @param {networks.Network} network - The Bitcoin network.\n * @param {number} amount - The amount to stake.\n * @returns {TransactionOutput[]} - The staking transaction outputs.\n * @throws {Error} - If the staking output cannot be built.\n */\nexport const buildStakingTransactionOutputs = (\n scripts: {\n timelockScript: Buffer;\n unbondingScript: Buffer;\n slashingScript: Buffer;\n dataEmbedScript?: Buffer;\n },\n network: networks.Network,\n amount: number,\n): TransactionOutput[] => {\n const stakingOutputInfo = deriveStakingOutputInfo(scripts, network);\n const transactionOutputs: { scriptPubKey: Buffer; value: number }[] = [\n {\n scriptPubKey: stakingOutputInfo.scriptPubKey,\n value: amount,\n },\n ];\n if (scripts.dataEmbedScript) {\n // Add the data embed output to the transaction\n transactionOutputs.push({\n scriptPubKey: scripts.dataEmbedScript,\n value: 0,\n });\n }\n return transactionOutputs;\n};\n\n/**\n * Derive the staking output address from the staking scripts.\n *\n * @param {StakingScripts} scripts - The staking scripts.\n * @param {networks.Network} network - The Bitcoin network.\n * @returns {StakingOutput} - The staking output address and scriptPubKey.\n * @throws {StakingError} - If the staking output address cannot be derived.\n */\nexport const deriveStakingOutputInfo = (\n scripts: {\n timelockScript: Buffer;\n unbondingScript: Buffer;\n slashingScript: Buffer;\n },\n network: networks.Network,\n) => {\n // Build outputs\n const scriptTree: Taptree = [\n {\n output: scripts.slashingScript,\n },\n [{ output: scripts.unbondingScript }, { output: scripts.timelockScript }],\n ];\n\n // Create an pay-2-taproot (p2tr) output using the staking script\n const stakingOutput = payments.p2tr({\n internalPubkey,\n scriptTree,\n network,\n });\n\n if (!stakingOutput.address) {\n throw new StakingError(\n StakingErrorCode.INVALID_OUTPUT,\n \"Failed to build staking output\",\n );\n }\n\n return {\n outputAddress: stakingOutput.address,\n scriptPubKey: address.toOutputScript(stakingOutput.address, network),\n };\n};\n\n/**\n * Derive the unbonding output address and scriptPubKey from the staking scripts.\n *\n * @param {StakingScripts} scripts - The staking scripts.\n * @param {networks.Network} network - The Bitcoin network.\n * @returns {OutputInfo} - The unbonding output address and scriptPubKey.\n * @throws {StakingError} - If the unbonding output address cannot be derived.\n */\nexport const deriveUnbondingOutputInfo = (\n scripts: {\n unbondingTimelockScript: Buffer;\n slashingScript: Buffer;\n },\n network: networks.Network,\n) => {\n const outputScriptTree: Taptree = [\n {\n output: scripts.slashingScript,\n },\n { output: scripts.unbondingTimelockScript },\n ];\n\n const unbondingOutput = payments.p2tr({\n internalPubkey,\n scriptTree: outputScriptTree,\n network,\n });\n\n if (!unbondingOutput.address) {\n throw new StakingError(\n StakingErrorCode.INVALID_OUTPUT,\n \"Failed to build unbonding output\",\n );\n }\n\n return {\n outputAddress: unbondingOutput.address,\n scriptPubKey: address.toOutputScript(unbondingOutput.address, network),\n };\n};\n\n/**\n * Derive the slashing output address and scriptPubKey from the staking scripts.\n *\n * @param {StakingScripts} scripts - The unbonding timelock scripts, we use the\n * unbonding timelock script as the timelock of the slashing transaction.\n * This is due to slashing tx timelock is the same as the unbonding timelock.\n * @param {networks.Network} network - The Bitcoin network.\n * @returns {OutputInfo} - The slashing output address and scriptPubKey.\n * @throws {StakingError} - If the slashing output address cannot be derived.\n */\nexport const deriveSlashingOutput = (\n scripts: {\n unbondingTimelockScript: Buffer;\n },\n network: networks.Network,\n) => {\n const slashingOutput = payments.p2tr({\n internalPubkey,\n scriptTree: { output: scripts.unbondingTimelockScript },\n network,\n });\n const slashingOutputAddress = slashingOutput.address;\n\n if (!slashingOutputAddress) {\n throw new StakingError(\n StakingErrorCode.INVALID_OUTPUT,\n \"Failed to build slashing output address\",\n );\n }\n\n return {\n outputAddress: slashingOutputAddress,\n scriptPubKey: address.toOutputScript(slashingOutputAddress, network),\n };\n};\n\n/**\n * Find the matching output index for the given transaction.\n *\n * @param {Transaction} tx - The transaction.\n * @param {string} outputAddress - The output address.\n * @param {networks.Network} network - The Bitcoin network.\n * @returns {number} - The output index.\n * @throws {Error} - If the matching output is not found.\n */\nexport const findMatchingTxOutputIndex = (\n tx: Transaction,\n outputAddress: string,\n network: networks.Network,\n) => {\n const index = tx.outs.findIndex((output) => {\n try {\n return address.fromOutputScript(output.script, network) === outputAddress;\n } catch (error) {\n return false;\n }\n });\n\n if (index === -1) {\n throw new StakingError(\n StakingErrorCode.INVALID_OUTPUT,\n `Matching output not found for address: ${outputAddress}`,\n );\n }\n\n return index;\n};\n\n/**\n * toBuffers converts an array of strings to an array of buffers.\n *\n * @param {string[]} inputs - The input strings.\n * @returns {Buffer[]} - The buffers.\n * @throws {StakingError} - If the values cannot be converted to buffers.\n */\nexport const toBuffers = (inputs: string[]): Buffer[] => {\n try {\n return inputs.map((i) => Buffer.from(i, \"hex\"));\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.INVALID_INPUT,\n \"Cannot convert values to buffers\",\n );\n }\n};\n\n\n/**\n * Strips all signatures from a transaction by clearing both the script and\n * witness data. This is due to the fact that we only need the raw unsigned\n * transaction structure. The signatures are sent in a separate protobuf field\n * when creating the delegation message in the Babylon.\n * @param tx - The transaction to strip signatures from\n * @returns A copy of the transaction with all signatures removed\n */\nexport const clearTxSignatures = (tx: Transaction): Transaction => {\n tx.ins.forEach((input) => {\n input.script = Buffer.alloc(0);\n input.witness = [];\n });\n return tx;\n};\n\n/**\n * Derives the merkle proof from the list of hex strings. Note the\n * sibling hashes are reversed from hex before concatenation.\n * @param merkle - The merkle proof hex strings.\n * @returns The merkle proof in hex string format.\n */\nexport const deriveMerkleProof = (merkle: string[]) => {\n const proofHex = merkle.reduce((acc: string, m: string) => {\n return acc + Buffer.from(m, \"hex\").reverse().toString(\"hex\");\n }, \"\");\n return proofHex;\n};\n\n/**\n * Extracts the first valid Schnorr signature from a signed transaction.\n *\n * Since we only handle transactions with a single input and request a signature\n * for one public key, there can be at most one signature from the Bitcoin node.\n * A valid Schnorr signature is exactly 64 bytes in length.\n *\n * @param singedTransaction - The signed Bitcoin transaction to extract the signature from\n * @returns The first valid 64-byte Schnorr signature found in the transaction witness data,\n * or undefined if no valid signature exists\n */\nexport const extractFirstSchnorrSignatureFromTransaction = (\n singedTransaction: Transaction,\n): Buffer | undefined => {\n // Loop through each input to extract the witness signature\n for (const input of singedTransaction.ins) {\n if (input.witness && input.witness.length > 0) {\n const schnorrSignature = input.witness[0];\n\n // Check that it's a 64-byte Schnorr signature\n if (schnorrSignature.length === 64) {\n return schnorrSignature; // Return the first valid signature found\n }\n }\n }\n return undefined;\n};\n", "// internalPubkey denotes an unspendable internal public key to be used for the taproot output\nconst key =\n \"0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0\";\nexport const internalPubkey = Buffer.from(key, \"hex\").subarray(1, 33); // Do a subarray(1, 33) to get the public coordinate\n", "import { Psbt, Transaction, networks, payments } from \"bitcoinjs-lib\";\nimport { Taptree } from \"bitcoinjs-lib/src/types\";\nimport { internalPubkey } from \"../constants/internalPubkey\";\nimport { NO_COORD_PK_BYTE_LENGTH } from \"../constants/keys\";\nimport { REDEEM_VERSION } from \"../constants/transaction\";\nimport { UTXO } from \"../types/UTXO\";\nimport { deriveUnbondingOutputInfo } from \"../utils/staking\";\nimport { findInputUTXO } from \"../utils/utxo/findInputUTXO\";\nimport { getPsbtInputFields } from \"../utils/utxo/getPsbtInputFields\";\nimport { BitcoinScriptType, getScriptType } from \"../utils/utxo/getScriptType\";\nimport { StakingScripts } from \"./stakingScript\";\n\n/**\n * Convert a staking transaction to a PSBT.\n *\n * @param {Transaction} stakingTx - The staking transaction to convert to PSBT.\n * @param {networks.Network} network - The network to use for the PSBT.\n * @param {UTXO[]} inputUTXOs - The UTXOs to be used as inputs for the staking\n * transaction.\n * @param {Buffer} [publicKeyNoCoord] - The public key of staker (optional)\n * @returns {Psbt} - The PSBT for the staking transaction.\n * @throws {Error} If unable to create PSBT from transaction\n */\nexport const stakingPsbt = (\n stakingTx: Transaction,\n network: networks.Network,\n inputUTXOs: UTXO[],\n publicKeyNoCoord?: Buffer,\n): Psbt => {\n if (publicKeyNoCoord && publicKeyNoCoord.length !== NO_COORD_PK_BYTE_LENGTH) {\n throw new Error(\"Invalid public key\");\n }\n\n const psbt = new Psbt({ network });\n\n if (stakingTx.version !== undefined) psbt.setVersion(stakingTx.version);\n if (stakingTx.locktime !== undefined) psbt.setLocktime(stakingTx.locktime);\n\n stakingTx.ins.forEach((input) => {\n const inputUTXO = findInputUTXO(inputUTXOs, input);\n const psbtInputData = getPsbtInputFields(inputUTXO, publicKeyNoCoord);\n\n psbt.addInput({\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n ...psbtInputData,\n });\n });\n\n stakingTx.outs.forEach((o) => {\n psbt.addOutput({ script: o.script, value: o.value });\n });\n\n return psbt;\n};\n\n/**\n * Convert a staking expansion transaction to a PSBT.\n *\n * @param {networks.Network} network - The Bitcoin network to use for the PSBT\n * @param {Transaction} stakingTx - The staking expansion transaction to convert\n * @param {Object} previousStakingTxInfo - Information about the previous staking transaction\n * @param {Transaction} previousStakingTxInfo.stakingTx - The previous staking transaction\n * @param {number} previousStakingTxInfo.outputIndex - The index of the staking output in the previous transaction\n * @param {UTXO[]} inputUTXOs - Available UTXOs for the funding input\n * @param {Buffer} [publicKeyNoCoord] - The staker's public key without coordinate (for Taproot)\n * @returns {Psbt} The PSBT for the staking expansion transaction\n * @throws {Error} If validation fails or required data is missing\n */\nexport const stakingExpansionPsbt = (\n network: networks.Network,\n stakingTx: Transaction,\n previousStakingTxInfo: {\n stakingTx: Transaction,\n outputIndex: number,\n },\n inputUTXOs: UTXO[],\n previousScripts: StakingScripts,\n publicKeyNoCoord?: Buffer,\n): Psbt => {\n // Initialize PSBT with the specified network\n const psbt = new Psbt({ network });\n \n // Set transaction version and locktime if provided\n if (stakingTx.version !== undefined) psbt.setVersion(stakingTx.version);\n if (stakingTx.locktime !== undefined) psbt.setLocktime(stakingTx.locktime);\n\n // Validate the public key format if provided\n if (\n publicKeyNoCoord && publicKeyNoCoord.length !== NO_COORD_PK_BYTE_LENGTH\n ) {\n throw new Error(\"Invalid public key\");\n }\n\n // Extract the previous staking output from the previous staking transaction\n const previousStakingOutput = previousStakingTxInfo.stakingTx.outs[\n previousStakingTxInfo.outputIndex\n ];\n if (!previousStakingOutput) {\n throw new Error(\"Previous staking output not found\");\n };\n \n // Validate that the previous staking output is a Taproot (P2TR) script\n if (\n getScriptType(previousStakingOutput.script) !== BitcoinScriptType.P2TR\n ) {\n throw new Error(\"Previous staking output script type is not P2TR\");\n }\n\n // Validate that the staking expansion transaction has exactly 2 inputs\n // Input 0: Previous staking output (existing stake)\n // Input 1: Funding UTXO (additional funds for fees or staking amount)\n if (stakingTx.ins.length !== 2) {\n throw new Error(\n \"Staking expansion transaction must have exactly 2 inputs\",\n );\n }\n\n // Validate the first input matches the previous staking transaction\n const txInputs = stakingTx.ins;\n \n // Check that the first input references the correct previous staking\n // transaction\n if (\n Buffer.from(txInputs[0].hash).reverse().toString(\"hex\") !== previousStakingTxInfo.stakingTx.getId()\n ) {\n throw new Error(\"Previous staking input hash does not match\");\n } \n // Check that the first input references the correct output index\n else if (txInputs[0].index !== previousStakingTxInfo.outputIndex) {\n throw new Error(\"Previous staking input index does not match\");\n }\n\n // Build input tapleaf script that spends the previous staking output\n const inputScriptTree: Taptree = [\n { output: previousScripts.slashingScript },\n [{ output: previousScripts.unbondingScript }, { output: previousScripts.timelockScript }],\n ];\n const inputRedeem = {\n output: previousScripts.unbondingScript,\n redeemVersion: REDEEM_VERSION,\n };\n const p2tr = payments.p2tr({\n internalPubkey,\n scriptTree: inputScriptTree,\n redeem: inputRedeem,\n network,\n });\n\n if (!p2tr.witness || p2tr.witness.length === 0) {\n throw new Error(\n \"Failed to create P2TR witness for expansion transaction input\"\n );\n }\n\n const inputTapLeafScript = {\n leafVersion: inputRedeem.redeemVersion,\n script: inputRedeem.output,\n controlBlock: p2tr.witness[p2tr.witness.length - 1],\n };\n\n // Add the previous staking input to the PSBT\n // This input spends the existing staking output\n psbt.addInput({\n hash: txInputs[0].hash,\n index: txInputs[0].index,\n sequence: txInputs[0].sequence,\n witnessUtxo: {\n script: previousStakingOutput.script,\n value: previousStakingOutput.value,\n },\n tapInternalKey: internalPubkey,\n tapLeafScript: [inputTapLeafScript],\n });\n\n // Add the second input (funding UTXO) to the PSBT\n // This input provides additional funds for fees or staking amount\n const inputUTXO = findInputUTXO(inputUTXOs, txInputs[1]);\n const psbtInputData = getPsbtInputFields(inputUTXO, publicKeyNoCoord);\n\n psbt.addInput({\n hash: txInputs[1].hash,\n index: txInputs[1].index,\n sequence: txInputs[1].sequence,\n ...psbtInputData,\n });\n\n // Add all outputs from the staking expansion transaction to the PSBT\n stakingTx.outs.forEach((o) => {\n psbt.addOutput({ script: o.script, value: o.value });\n });\n\n return psbt;\n};\n\nexport const unbondingPsbt = (\n scripts: {\n unbondingScript: Buffer;\n timelockScript: Buffer;\n slashingScript: Buffer;\n unbondingTimelockScript: Buffer;\n },\n unbondingTx: Transaction,\n stakingTx: Transaction,\n network: networks.Network,\n): Psbt => {\n if (unbondingTx.outs.length !== 1) {\n throw new Error(\"Unbonding transaction must have exactly one output\");\n }\n if (unbondingTx.ins.length !== 1) {\n throw new Error(\"Unbonding transaction must have exactly one input\");\n }\n\n validateUnbondingOutput(scripts, unbondingTx, network);\n\n const psbt = new Psbt({ network });\n\n if (unbondingTx.version !== undefined) {\n psbt.setVersion(unbondingTx.version);\n }\n if (unbondingTx.locktime !== undefined) {\n psbt.setLocktime(unbondingTx.locktime);\n }\n\n const input = unbondingTx.ins[0];\n const outputIndex = input.index;\n\n // Build input tapleaf script\n const inputScriptTree: Taptree = [\n { output: scripts.slashingScript },\n [{ output: scripts.unbondingScript }, { output: scripts.timelockScript }],\n ];\n\n // This is the tapleaf we are actually spending\n const inputRedeem = {\n output: scripts.unbondingScript,\n redeemVersion: REDEEM_VERSION,\n };\n\n // Create a P2TR payment that includes scriptTree + redeem\n const p2tr = payments.p2tr({\n internalPubkey,\n scriptTree: inputScriptTree,\n redeem: inputRedeem,\n network,\n });\n\n const inputTapLeafScript = {\n leafVersion: inputRedeem.redeemVersion,\n script: inputRedeem.output,\n controlBlock: p2tr.witness![p2tr.witness!.length - 1],\n };\n\n psbt.addInput({\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n tapInternalKey: internalPubkey,\n witnessUtxo: {\n value: stakingTx.outs[outputIndex].value,\n script: stakingTx.outs[outputIndex].script,\n },\n tapLeafScript: [inputTapLeafScript],\n });\n\n psbt.addOutput({\n script: unbondingTx.outs[0].script,\n value: unbondingTx.outs[0].value,\n });\n\n return psbt;\n};\n\n/**\n * Validate the unbonding output for a given unbonding transaction.\n *\n * @param {Object} scripts - The scripts to use for the unbonding output.\n * @param {Transaction} unbondingTx - The unbonding transaction.\n * @param {networks.Network} network - The network to use for the unbonding output.\n */\nconst validateUnbondingOutput = (\n scripts: {\n slashingScript: Buffer;\n unbondingTimelockScript: Buffer;\n },\n unbondingTx: Transaction,\n network: networks.Network,\n) => {\n const unbondingOutputInfo = deriveUnbondingOutputInfo(scripts, network);\n if (\n unbondingOutputInfo.scriptPubKey.toString(\"hex\") !==\n unbondingTx.outs[0].script.toString(\"hex\")\n ) {\n throw new Error(\n \"Unbonding output script does not match the expected\" +\n \" script while building psbt\",\n );\n }\n};\n", "export const REDEEM_VERSION = 192;", "import { Input } from \"bitcoinjs-lib/src/transaction\";\n\nimport { UTXO } from \"../../types/UTXO\";\nimport { transactionIdToHash } from \"../btc\";\n\nexport const findInputUTXO = (inputUTXOs: UTXO[], input: Input): UTXO => {\n const inputUTXO = inputUTXOs.find(\n (u) =>\n transactionIdToHash(u.txid).toString(\"hex\") ===\n input.hash.toString(\"hex\") && u.vout === input.index,\n );\n if (!inputUTXO) {\n throw new Error(\n `Input UTXO not found for txid: ${Buffer.from(input.hash).reverse().toString(\"hex\")} ` +\n `and vout: ${input.index}`,\n );\n }\n return inputUTXO;\n};\n", "import { payments } from \"bitcoinjs-lib\";\n\n/**\n * Supported Bitcoin script types\n */\nexport enum BitcoinScriptType {\n // Pay to Public Key Hash\n P2PKH = \"pubkeyhash\",\n // Pay to Script Hash\n P2SH = \"scripthash\",\n // Pay to Witness Public Key Hash\n P2WPKH = \"witnesspubkeyhash\",\n // Pay to Witness Script Hash\n P2WSH = \"witnessscripthash\",\n // Pay to Taproot\n P2TR = \"taproot\",\n}\n\n/**\n * Determines the type of Bitcoin script.\n *\n * This function tries to parse the script using different Bitcoin payment types and returns\n * a string identifier for the script type.\n *\n * @param script - The raw script as a Buffer\n * @returns {BitcoinScriptType} The identified script type\n * @throws {Error} If the script cannot be identified as any known type\n */\n\nexport const getScriptType = (script: Buffer): BitcoinScriptType => {\n try {\n payments.p2pkh({ output: script });\n return BitcoinScriptType.P2PKH;\n } catch {}\n try {\n payments.p2sh({ output: script });\n return BitcoinScriptType.P2SH;\n } catch {}\n try {\n payments.p2wpkh({ output: script });\n return BitcoinScriptType.P2WPKH;\n } catch {}\n try {\n payments.p2wsh({ output: script });\n return BitcoinScriptType.P2WSH;\n } catch {}\n try {\n payments.p2tr({ output: script });\n return BitcoinScriptType.P2TR;\n } catch {}\n\n throw new Error(\"Unknown script type\");\n};\n", "import { PsbtInputExtended } from \"bip174/src/lib/interfaces\";\n\nimport { UTXO } from \"../../types\";\nimport { BitcoinScriptType, getScriptType } from \"./getScriptType\";\n\n/**\n * Determines and constructs the correct PSBT input fields for a given UTXO based on its script type.\n * This function handles different Bitcoin script types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR) and returns\n * the appropriate PSBT input fields required for that UTXO.\n *\n * @param {UTXO} utxo - The unspent transaction output to process\n * @param {Buffer} [publicKeyNoCoord] - The public of the staker (optional).\n * @returns {object} PSBT input fields object containing the necessary data\n * @throws {Error} If required input data is missing or if an unsupported script type is provided\n */\n\nexport const getPsbtInputFields = (\n utxo: UTXO,\n publicKeyNoCoord?: Buffer,\n): PsbtInputExtended => {\n const scriptPubKey = Buffer.from(utxo.scriptPubKey, \"hex\");\n const type = getScriptType(scriptPubKey);\n\n switch (type) {\n case BitcoinScriptType.P2PKH: {\n if (!utxo.rawTxHex) {\n throw new Error(\"Missing rawTxHex for legacy P2PKH input\");\n }\n return { nonWitnessUtxo: Buffer.from(utxo.rawTxHex, \"hex\") };\n }\n case BitcoinScriptType.P2SH: {\n if (!utxo.rawTxHex) {\n throw new Error(\"Missing rawTxHex for P2SH input\");\n }\n if (!utxo.redeemScript) {\n throw new Error(\"Missing redeemScript for P2SH input\");\n }\n return {\n nonWitnessUtxo: Buffer.from(utxo.rawTxHex, \"hex\"),\n redeemScript: Buffer.from(utxo.redeemScript, \"hex\"),\n };\n }\n case BitcoinScriptType.P2WPKH: {\n return {\n witnessUtxo: {\n script: scriptPubKey,\n value: utxo.value,\n },\n };\n }\n case BitcoinScriptType.P2WSH: {\n if (!utxo.witnessScript) {\n throw new Error(\"Missing witnessScript for P2WSH input\");\n }\n return {\n witnessUtxo: {\n script: scriptPubKey,\n value: utxo.value,\n },\n witnessScript: Buffer.from(utxo.witnessScript, \"hex\"),\n };\n }\n case BitcoinScriptType.P2TR: {\n return {\n witnessUtxo: {\n script: scriptPubKey,\n value: utxo.value,\n },\n // this is needed only if the wallet is in taproot mode\n ...(publicKeyNoCoord && { tapInternalKey: publicKeyNoCoord }),\n };\n }\n default:\n throw new Error(`Unsupported script type: ${type}`);\n }\n};\n", "import { opcodes, script } from \"bitcoinjs-lib\";\nimport { NO_COORD_PK_BYTE_LENGTH } from \"../constants/keys\";\n\nexport const MAGIC_BYTES_LEN = 4;\n\n// Represents the staking scripts used in BTC staking.\nexport interface StakingScripts {\n timelockScript: Buffer;\n unbondingScript: Buffer;\n slashingScript: Buffer;\n unbondingTimelockScript: Buffer;\n}\n\n// StakingScriptData is a class that holds the data required for the BTC Staking Script\n// and exposes methods for converting it into useful formats\nexport class StakingScriptData {\n stakerKey: Buffer;\n finalityProviderKeys: Buffer[];\n covenantKeys: Buffer[];\n covenantThreshold: number;\n stakingTimeLock: number;\n unbondingTimeLock: number;\n\n constructor(\n // The `stakerKey` is the public key of the staker without the coordinate bytes.\n stakerKey: Buffer,\n // A list of public keys without the coordinate bytes corresponding to the finality providers\n // the stake will be delegated to.\n // Currently, Babylon does not support restaking, so this should contain only a single item.\n finalityProviderKeys: Buffer[],\n // A list of the public keys without the coordinate bytes corresponding to\n // the covenant emulators.\n // This is a parameter of the Babylon system and should be retrieved from there.\n covenantKeys: Buffer[],\n // The number of covenant emulator signatures required for a transaction\n // to be valid.\n // This is a parameter of the Babylon system and should be retrieved from there.\n covenantThreshold: number,\n // The staking period denoted as a number of BTC blocks.\n stakingTimelock: number,\n // The unbonding period denoted as a number of BTC blocks.\n // This value should be more than equal than the minimum unbonding time of the\n // Babylon system.\n unbondingTimelock: number,\n ) {\n if (\n !stakerKey ||\n !finalityProviderKeys ||\n !covenantKeys ||\n !covenantThreshold ||\n !stakingTimelock ||\n !unbondingTimelock\n ) {\n throw new Error(\"Missing required input values\");\n }\n this.stakerKey = stakerKey;\n this.finalityProviderKeys = finalityProviderKeys;\n this.covenantKeys = covenantKeys;\n this.covenantThreshold = covenantThreshold;\n this.stakingTimeLock = stakingTimelock;\n this.unbondingTimeLock = unbondingTimelock;\n\n // Run the validate method to check if the provided script data is valid\n if (!this.validate()) {\n throw new Error(\"Invalid script data provided\");\n }\n }\n\n /**\n * Validates the staking script.\n * @returns {boolean} Returns true if the staking script is valid, otherwise false.\n */\n validate(): boolean {\n // check that staker key is the correct length\n if (this.stakerKey.length != NO_COORD_PK_BYTE_LENGTH) {\n return false;\n }\n // check that finalityProvider keys are the correct length\n if (\n this.finalityProviderKeys.some(\n (finalityProviderKey) => finalityProviderKey.length != NO_COORD_PK_BYTE_LENGTH,\n )\n ) {\n return false;\n }\n // check that covenant keys are the correct length\n if (\n this.covenantKeys.some((covenantKey) => covenantKey.length != NO_COORD_PK_BYTE_LENGTH)\n ) {\n return false;\n }\n\n // Check whether we have any duplicate keys\n const allPks = [\n this.stakerKey,\n ...this.finalityProviderKeys,\n ...this.covenantKeys,\n ];\n const allPksSet = new Set(allPks);\n if (allPks.length !== allPksSet.size) {\n return false;\n }\n\n // check that the threshold is above 0 and less than or equal to\n // the size of the covenant emulators set\n if (\n this.covenantThreshold <= 0 ||\n this.covenantThreshold > this.covenantKeys.length\n ) {\n return false;\n }\n\n // check that maximum value for staking time is not greater than uint16 and above 0\n if (this.stakingTimeLock <= 0 || this.stakingTimeLock > 65535) {\n return false;\n }\n\n // check that maximum value for unbonding time is not greater than uint16 and above 0\n if (this.unbondingTimeLock <= 0 || this.unbondingTimeLock > 65535) {\n return false;\n }\n\n return true;\n }\n\n // The staking script allows for multiple finality provider public keys\n // to support (re)stake to multiple finality providers\n // Covenant members are going to have multiple keys\n\n /**\n * Builds a timelock script.\n * @param timelock - The timelock value to encode in the script.\n * @returns {Buffer} containing the compiled timelock script.\n */\n buildTimelockScript(timelock: number): Buffer {\n return script.compile([\n this.stakerKey,\n opcodes.OP_CHECKSIGVERIFY,\n script.number.encode(timelock),\n opcodes.OP_CHECKSEQUENCEVERIFY,\n ]);\n }\n\n /**\n * Builds the staking timelock script.\n * Only holder of private key for given pubKey can spend after relative lock time\n * Creates the timelock script in the form:\n * <stakerPubKey>\n * OP_CHECKSIGVERIFY\n * <stakingTimeBlocks>\n * OP_CHECKSEQUENCEVERIFY\n * @returns {Buffer} The staking timelock script.\n */\n buildStakingTimelockScript(): Buffer {\n return this.buildTimelockScript(this.stakingTimeLock);\n }\n\n /**\n * Builds the unbonding timelock script.\n * Creates the unbonding timelock script in the form:\n * <stakerPubKey>\n * OP_CHECKSIGVERIFY\n * <unbondingTimeBlocks>\n * OP_CHECKSEQUENCEVERIFY\n * @returns {Buffer} The unbonding timelock script.\n */\n buildUnbondingTimelockScript(): Buffer {\n return this.buildTimelockScript(this.unbondingTimeLock);\n }\n\n /**\n * Builds the unbonding script in the form:\n * buildSingleKeyScript(stakerPk, true) ||\n * buildMultiKeyScript(covenantPks, covenantThreshold, false)\n * || means combining the scripts\n * @returns {Buffer} The unbonding script.\n */\n buildUnbondingScript(): Buffer {\n return Buffer.concat([\n this.buildSingleKeyScript(this.stakerKey, true),\n this.buildMultiKeyScript(\n this.covenantKeys,\n this.covenantThreshold,\n false,\n ),\n ]);\n }\n\n /**\n * Builds the slashing script for staking in the form:\n * buildSingleKeyScript(stakerPk, true) ||\n * buildMultiKeyScript(finalityProviderPKs, 1, true) ||\n * buildMultiKeyScript(covenantPks, covenantThreshold, false)\n * || means combining the scripts\n * The slashing script is a combination of single-key and multi-key scripts.\n * The single-key script is used for staker key verification.\n * The multi-key script is used for finality provider key verification and covenant key verification.\n * @returns {Buffer} The slashing script as a Buffer.\n */\n buildSlashingScript(): Buffer {\n return Buffer.concat([\n this.buildSingleKeyScript(this.stakerKey, true),\n this.buildMultiKeyScript(\n this.finalityProviderKeys,\n // The threshold is always 1 as we only need one\n // finalityProvider signature to perform slashing\n // (only one finalityProvider performs an offence)\n 1,\n // OP_VERIFY/OP_CHECKSIGVERIFY is added at the end\n true,\n ),\n this.buildMultiKeyScript(\n this.covenantKeys,\n this.covenantThreshold,\n // No need to add verify since covenants are at the end of the script\n false,\n ),\n ]);\n }\n /**\n * Builds the staking scripts.\n * @returns {StakingScripts} The staking scripts.\n */\n buildScripts(): StakingScripts {\n return {\n timelockScript: this.buildStakingTimelockScript(),\n unbondingScript: this.buildUnbondingScript(),\n slashingScript: this.buildSlashingScript(),\n unbondingTimelockScript: this.buildUnbondingTimelockScript(),\n };\n }\n\n // buildSingleKeyScript and buildMultiKeyScript allow us to reuse functionality\n // for creating Bitcoin scripts for the unbonding script and the slashing script\n\n /**\n * Builds a single key script in the form:\n * buildSingleKeyScript creates a single key script\n * <pk> OP_CHECKSIGVERIFY (if withVerify is true)\n * <pk> OP_CHECKSIG (if withVerify is false)\n * @param pk - The public key buffer.\n * @param withVerify - A boolean indicating whether to include the OP_CHECKSIGVERIFY opcode.\n * @returns The compiled script buffer.\n */\n buildSingleKeyScript(pk: Buffer, withVerify: boolean): Buffer {\n // Check public key length\n if (pk.length != NO_COORD_PK_BYTE_LENGTH) {\n throw new Error(\"Invalid key length\");\n }\n return script.compile([\n pk,\n withVerify ? opcodes.OP_CHECKSIGVERIFY : opcodes.OP_CHECKSIG,\n ]);\n }\n\n /**\n * Builds a multi-key script in the form:\n * <pk1> OP_CHEKCSIG <pk2> OP_CHECKSIGADD <pk3> OP_CHECKSIGADD ... <pkN> OP_CHECKSIGADD <threshold> OP_NUMEQUAL\n * <withVerify -> OP_NUMEQUALVERIFY>\n * It validates whether provided keys are unique and the threshold is not greater than number of keys\n * If there is only one key provided it will return single key sig script\n * @param pks - An array of public keys.\n * @param threshold - The required number of valid signers.\n * @param withVerify - A boolean indicating whether to include the OP_VERIFY opcode.\n * @returns The compiled multi-key script as a Buffer.\n * @throws {Error} If no keys are provided, if the required number of valid signers is greater than the number of provided keys, or if duplicate keys are provided.\n */\n buildMultiKeyScript(\n pks: Buffer[],\n threshold: number,\n withVerify: boolean,\n ): Buffer {\n // Verify that pks is not empty\n if (!pks || pks.length === 0) {\n throw new Error(\"No keys provided\");\n }\n // Check buffer object have expected lengths like checking pks.length\n if (pks.some((pk) => pk.length != NO_COORD_PK_BYTE_LENGTH)) {\n throw new Error(\"Invalid key length\");\n }\n // Verify that threshold <= len(pks)\n if (threshold > pks.length) {\n throw new Error(\n \"Required number of valid signers is greater than number of provided keys\",\n );\n }\n if (pks.length === 1) {\n return this.buildSingleKeyScript(pks[0], withVerify);\n }\n // keys must be sorted\n const sortedPks = [...pks].sort(Buffer.compare);\n // verify there are no duplicates\n for (let i = 0; i < sortedPks.length - 1; ++i) {\n if (sortedPks[i].equals(sortedPks[i + 1])) {\n throw new Error(\"Duplicate keys provided\");\n }\n }\n const scriptElements = [sortedPks[0], opcodes.OP_CHECKSIG];\n for (let i = 1; i < sortedPks.length; i++) {\n scriptElements.push(sortedPks[i]);\n scriptElements.push(opcodes.OP_CHECKSIGADD);\n }\n scriptElements.push(script.number.encode(threshold));\n if (withVerify) {\n scriptElements.push(opcodes.OP_NUMEQUALVERIFY);\n } else {\n scriptElements.push(opcodes.OP_NUMEQUAL);\n }\n return script.compile(scriptElements);\n }\n}\n", "import {\n Psbt, Transaction, networks, payments, script, address, opcodes\n} from \"bitcoinjs-lib\";\nimport { Taptree } from \"bitcoinjs-lib/src/types\";\n\nimport { BTC_DUST_SAT } from \"../constants/dustSat\";\nimport { internalPubkey } from \"../constants/internalPubkey\";\nimport { UTXO } from \"../types/UTXO\";\nimport { PsbtResult, TransactionResult } from \"../types/transaction\";\nimport { isValidBitcoinAddress, transactionIdToHash } from \"../utils/btc\";\nimport {\n getStakingExpansionTxFundingUTXOAndFees,\n getStakingTxInputUTXOsAndFees,\n getWithdrawTxFee,\n} from \"../utils/fee\";\nimport { inputValueSum } from \"../utils/fee/utils\";\nimport {\n buildStakingTransactionOutputs,\n deriveStakingOutputInfo,\n deriveUnbondingOutputInfo,\n findMatchingTxOutputIndex,\n} from \"../utils/staking\";\nimport { NON_RBF_SEQUENCE, TRANSACTION_VERSION } from \"../constants/psbt\";\nimport { CovenantSignature } from \"../types/covenantSignatures\";\nimport { REDEEM_VERSION } from \"../constants/transaction\";\n\n// https://bips.xyz/370\nconst BTC_LOCKTIME_HEIGHT_TIME_CUTOFF = 500000000;\nconst BTC_SLASHING_FRACTION_DIGITS = 4;\n\n/**\n * Constructs an unsigned BTC Staking transaction in psbt format.\n *\n * Outputs:\n * - psbt:\n * - The first output corresponds to the staking script with the specified amount.\n * - The second output corresponds to the change from spending the amount and the transaction fee.\n * - If a data embed script is provided, it will be added as the second output, and the fee will be the third output.\n * - fee: The total fee amount for the transaction.\n *\n * Inputs:\n * - scripts:\n * - timelockScript, unbondingScript, slashingScript: Scripts for different transaction types.\n * - dataEmbedScript: Optional data embed script.\n * - amount: Amount to stake.\n * - changeAddress: Address to send the change to.\n * - inputUTXOs: All available UTXOs from the wallet.\n * - network: Bitcoin network.\n * - feeRate: Fee rate in satoshis per byte.\n * - publicKeyNoCoord: Public key if the wallet is in taproot mode.\n * - lockHeight: Optional block height locktime to set for the transaction (i.e., not mined until the block height).\n *\n * @param {Object} scripts - Scripts used to construct the taproot output.\n * such as timelockScript, unbondingScript, slashingScript, and dataEmbedScript.\n * @param {number} amount - The amount to stake.\n * @param {string} changeAddress - The address to send the change to.\n * @param {UTXO[]} inputUTXOs - All available UTXOs from the wallet.\n * @param {networks.Network} network - The Bitcoin network.\n * @param {number} feeRate - The fee rate in satoshis per byte.\n * @param {number} [lockHeight] - The optional block height locktime.\n * @returns {TransactionResult} - An object containing the unsigned transaction and fee\n * @throws Will throw an error if the amount or fee rate is less than or equal\n * to 0, if the change address is invalid, or if the public key is invalid.\n */\nexport function stakingTransaction(\n scripts: {\n timelockScript: Buffer;\n unbondingScript: Buffer;\n slashingScript: Buffer;\n dataEmbedScript?: Buffer;\n },\n amount: number,\n changeAddress: string,\n inputUTXOs: UTXO[],\n network: networks.Network,\n feeRate: number,\n lockHeight?: number,\n): TransactionResult {\n // Check that amount and fee are bigger than 0\n if (amount <= 0 || feeRate <= 0) {\n throw new Error(\"Amount and fee rate must be bigger than 0\");\n }\n\n // Check whether the change address is a valid Bitcoin address.\n if (!isValidBitcoinAddress(changeAddress, network)) {\n throw new Error(\"Invalid change address\");\n }\n\n // Build outputs and estimate the fee\n const stakingOutputs = buildStakingTransactionOutputs(scripts, network, amount);\n const { selectedUTXOs, fee } = getStakingTxInputUTXOsAndFees(\n inputUTXOs,\n amount,\n feeRate,\n stakingOutputs,\n );\n\n const tx = new Transaction();\n tx.version = TRANSACTION_VERSION;\n \n for (let i = 0; i < selectedUTXOs.length; ++i) {\n const input = selectedUTXOs[i];\n tx.addInput(\n transactionIdToHash(input.txid),\n input.vout,\n NON_RBF_SEQUENCE,\n );\n }\n\n stakingOutputs.forEach((o) => {\n tx.addOutput(o.scriptPubKey, o.value);\n });\n\n // Add a change output only if there's any amount leftover from the inputs\n const inputsSum = inputValueSum(selectedUTXOs);\n // Check if the change amount is above the dust limit, and if so, add it as a change output\n if (inputsSum - (amount + fee) > BTC_DUST_SAT) {\n tx.addOutput(\n address.toOutputScript(changeAddress, network),\n inputsSum - (amount + fee),\n );\n }\n\n // Set the locktime field if provided. If not provided, the locktime will be set to 0 by default\n // Only height based locktime is supported\n if (lockHeight) {\n if (lockHeight >= BTC_LOCKTIME_HEIGHT_TIME_CUTOFF) {\n throw new Error(\"Invalid lock height\");\n }\n tx.locktime = lockHeight;\n }\n\n return {\n transaction: tx,\n fee,\n };\n}\n\n/**\n * Expand an existing staking transaction with additional finality providers\n * or renew timelock.\n * \n * This function builds a Bitcoin transaction that:\n * 1. Spends the previous staking transaction output as the first input\n * 2. Uses a funding UTXO as the second input to cover transaction fees\n * 3. Creates new staking outputs where the timelock is renewed or FPs added\n * 4. Returns any remaining funds as change\n * \n * @param network - Bitcoin network (mainnet, testnet, etc.)\n * @param scripts - Scripts for the new staking outputs\n * @param amount - Total staking amount (must equal previous staking amount,\n * we only support equal amounts for now)\n * @param changeAddress - Bitcoin address to receive change from funding UTXO\n * @param feeRate - Fee rate in satoshis per byte\n * @param inputUTXOs - Available UTXOs to use for funding the expansion\n * @param previousStakingTxInfo - Details of the previous staking transaction\n * being expanded\n * @returns {TransactionResult & { fundingUTXO: UTXO }} containing the built\n * transaction and calculated fee, and the funding UTXO\n */\nexport function stakingExpansionTransaction(\n network: networks.Network,\n scripts: {\n timelockScript: Buffer;\n unbondingScript: Buffer;\n slashingScript: Buffer;\n },\n amount: number,\n changeAddress: string,\n feeRate: number,\n inputUTXOs: UTXO[],\n previousStakingTxInfo: {\n stakingTx: Transaction,\n scripts: {\n timelockScript: Buffer;\n unbondingScript: Buffer;\n slashingScript: Buffer;\n },\n },\n): TransactionResult & {\n fundingUTXO: UTXO;\n} {\n // Validate input parameters\n if (amount <= 0 || feeRate <= 0) {\n throw new Error(\"Amount and fee rate must be bigger than 0\");\n } else if (!isValidBitcoinAddress(changeAddress, network)) {\n throw new Error(\"Invalid BTC change address\");\n }\n \n // Derive the output address and amount from the previous staking transaction\n // scripts. This helps us locate the specific output in the previous\n // transaction\n const previousStakingOutputInfo = deriveStakingOutputInfo(\n previousStakingTxInfo.scripts, network\n );\n \n // Find the output index of the previous staking transaction in the\n // transaction outputs. This method will throw an error if the output\n // is not found.\n const previousStakingOutputIndex = findMatchingTxOutputIndex(\n previousStakingTxInfo.stakingTx,\n previousStakingOutputInfo.outputAddress,\n network\n );\n \n // Extract the actual staking amount from the previous transaction output\n const previousStakingAmount = previousStakingTxInfo.stakingTx.outs[\n previousStakingOutputIndex\n ].value;\n \n // Validate that the expansion amount matches the previous staking amount\n // According to Babylon protocol, expansion amount must be >= previous amount\n // Currently, this library only supports equal amounts (no stake increase)\n if (amount !== previousStakingAmount) {\n throw new Error(\n \"Expansion staking transaction amount must be equal to the previous \"\n + \"staking amount. Increase of the staking amount is not supported yet.\",\n );\n }\n\n // Build the staking outputs for the expansion transaction\n // These outputs will contain the new scripts with expanded timelock or FPs\n const stakingOutputs = buildStakingTransactionOutputs(\n scripts, network, amount,\n );\n\n // Select a single funding UTXO and calculate the required fee\n // The funding UTXO will be used as the second input to cover transaction fees\n const { selectedUTXO, fee } = getStakingExpansionTxFundingUTXOAndFees(\n inputUTXOs,\n feeRate,\n stakingOutputs,\n );\n\n // Initialize the transaction with the standard version\n const tx = new Transaction();\n tx.version = TRANSACTION_VERSION;\n \n // Add the first input: previous staking transaction output\n // This is the existing stake that we're expanding\n tx.addInput(\n previousStakingTxInfo.stakingTx.getHash(),\n previousStakingOutputIndex,\n NON_RBF_SEQUENCE,\n );\n \n // Add the second input: selected funding UTXO\n // This provides the funds to cover transaction fees\n tx.addInput(\n transactionIdToHash(selectedUTXO.txid),\n selectedUTXO.vout,\n NON_RBF_SEQUENCE,\n );\n\n // Add all staking outputs to the transaction\n // These represent the expanded stake with new finality provider coverage\n stakingOutputs.forEach((o) => {\n tx.addOutput(o.scriptPubKey, o.value);\n });\n\n // Add a change output if there are remaining funds from the funding UTXO\n // Only create change if the remaining amount is above the dust threshold\n if (selectedUTXO.value - fee > BTC_DUST_SAT) {\n tx.addOutput(\n address.toOutputScript(changeAddress, network),\n selectedUTXO.value - fee,\n );\n }\n\n return {\n transaction: tx,\n fee,\n fundingUTXO: selectedUTXO,\n };\n}\n\n/**\n * Constructs a withdrawal transaction for manually unbonded delegation.\n *\n * This transaction spends the unbonded output from the staking transaction.\n *\n * Inputs:\n * - scripts: Scripts used to construct the taproot output.\n * - unbondingTimelockScript: Script for the unbonding timelock condition.\n * - slashingScript: Script for the slashing condition.\n * - unbondingTx: The unbonding transaction.\n * - withdrawalAddress: The address to send the withdrawn funds to.\n * - network: The Bitcoin network.\n * - feeRate: The fee rate for the transaction in satoshis per byte.\n *\n * Returns:\n * - psbt: The partially signed transaction (PSBT).\n *\n * @param {Object} scripts - The scripts used in the transaction.\n * @param {Transaction} unbondingTx - The unbonding transaction.\n * @param {string} withdrawalAddress - The address to send the withdrawn funds to.\n * @param {networks.Network} network - The Bitcoin network.\n * @param {number} feeRate - The fee rate for the transaction in satoshis per byte.\n * @returns {PsbtResult} An object containing the partially signed transaction (PSBT).\n */\nexport function withdrawEarlyUnbondedTransaction(\n scripts: {\n unbondingTimelockScript: Buffer;\n slashingScript: Buffer;\n },\n unbondingTx: Transaction,\n withdrawalAddress: string,\n network: networks.Network,\n feeRate: number,\n): PsbtResult {\n const scriptTree: Taptree = [\n {\n output: scripts.slashingScript,\n },\n { output: scripts.unbondingTimelockScript },\n ];\n\n return withdrawalTransaction(\n {\n timelockScript: scripts.unbondingTimelockScript,\n },\n scriptTree,\n unbondingTx,\n withdrawalAddress,\n network,\n feeRate,\n 0, // unbonding always has a single output\n );\n}\n\n/**\n * Constructs a withdrawal transaction for naturally unbonded delegation.\n *\n * This transaction spends the unbonded output from the staking transaction when the timelock has expired.\n *\n * Inputs:\n * - scripts: Scripts used to construct the taproot output.\n * - timelockScript: Script for the timelock condition.\n * - slashingScript: Script for the slashing condition.\n * - unbondingScript: Script for the unbonding condition.\n * - tx: The original staking transaction.\n * - withdrawalAddress: The address to send the withdrawn funds to.\n * - network: The Bitcoin network.\n * - feeRate: The fee rate for the transaction in satoshis per byte.\n * - outputIndex: The index of the output to be spent in the original transaction (default is 0).\n *\n * Returns:\n * - psbt: The partially signed transaction (PSBT).\n *\n * @param {Object} scripts - The scripts used in the transaction.\n * @param {Transaction} tx - The original staking transaction.\n * @param {string} withdrawalAddress - The address to send the withdrawn funds to.\n * @param {networks.Network} network - The Bitcoin network.\n * @param {number} feeRate - The fee rate for the transaction in satoshis per byte.\n * @param {number} [outputIndex=0] - The index of the output to be spent in the original transaction.\n * @returns {PsbtResult} An object containing the partially signed transaction (PSBT).\n */\nexport function withdrawTimelockUnbondedTransaction(\n scripts: {\n timelockScript: Buffer;\n slashingScript: Buffer;\n unbondingScript: Buffer;\n },\n tx: Transaction,\n withdrawalAddress: string,\n network: networks.Network,\n feeRate: number,\n outputIndex: number = 0,\n): PsbtResult {\n const scriptTree: Taptree = [\n {\n output: scripts.slashingScript,\n },\n [{ output: scripts.unbondingScript }, { output: scripts.timelockScript }],\n ];\n\n return withdrawalTransaction(\n scripts,\n scriptTree,\n tx,\n withdrawalAddress,\n network,\n feeRate,\n outputIndex,\n );\n}\n\n/**\n * Constructs a withdrawal transaction for a slashing transaction.\n *\n * This transaction spends the output from the slashing transaction.\n *\n * @param {Object} scripts - The unbondingTimelockScript\n * We use the unbonding timelock script as the timelock of the slashing transaction.\n * This is due to slashing tx timelock is the same as the unbonding timelock.\n * @param {Transaction} slashingTx - The slashing transaction.\n * @param {string} withdrawalAddress - The address to send the withdrawn funds to.\n * @param {networks.Network} network - The Bitcoin network.\n * @param {number} feeRate - The fee rate for the transaction in satoshis per byte.\n * @param {number} outputIndex - The index of the output to be spent in the original transaction.\n * @returns {PsbtResult} An object containing the partially signed transaction (PSBT).\n */\nexport function withdrawSlashingTransaction(\n scripts: {\n unbondingTimelockScript: Buffer;\n },\n slashingTx: Transaction,\n withdrawalAddress: string,\n network: networks.Network,\n feeRate: number,\n outputIndex: number,\n): PsbtResult {\n const scriptTree: Taptree = { output: scripts.unbondingTimelockScript };\n\n return withdrawalTransaction(\n {\n timelockScript: scripts.unbondingTimelockScript,\n },\n scriptTree,\n slashingTx,\n withdrawalAddress,\n network,\n feeRate,\n outputIndex,\n );\n}\n\n// withdrawalTransaction generates a transaction that\n// spends the staking output of the staking transaction\nfunction withdrawalTransaction(\n scripts: {\n timelockScript: Buffer;\n },\n scriptTree: Taptree,\n tx: Transaction,\n withdrawalAddress: string,\n network: networks.Network,\n feeRate: number,\n outputIndex: number = 0,\n): PsbtResult {\n // Check that withdrawal feeRate is bigger than 0\n if (feeRate <= 0) {\n throw new Error(\"Withdrawal feeRate must be bigger than 0\");\n }\n\n // Check that outputIndex is bigger or equal to 0\n if (outputIndex < 0) {\n throw new Error(\"Output index must be bigger or equal to 0\");\n }\n\n // position of time in the timelock script\n const timePosition = 2;\n const decompiled = script.decompile(scripts.timelockScript);\n\n if (!decompiled) {\n throw new Error(\"Timelock script is not valid\");\n }\n\n let timelock = 0;\n\n // if the timelock is a buffer, it means it's a number bigger than 16 blocks\n if (typeof decompiled[timePosition] !== \"number\") {\n const timeBuffer = decompiled[timePosition] as Buffer;\n timelock = script.number.decode(timeBuffer);\n } else {\n // in case timelock is <= 16 it will be a number, not a buffer\n const wrap = decompiled[timePosition] % 16;\n timelock = wrap === 0 ? 16 : wrap;\n }\n\n const redeem = {\n output: scripts.timelockScript,\n redeemVersion: REDEEM_VERSION,\n };\n\n const p2tr = payments.p2tr({\n internalPubkey,\n scriptTree,\n redeem,\n network,\n });\n\n const tapLeafScript = {\n leafVersion: redeem.redeemVersion,\n script: redeem.output,\n controlBlock: p2tr.witness![p2tr.witness!.length - 1],\n };\n\n const psbt = new Psbt({ network });\n\n // only transactions with version 2 can trigger OP_CHECKSEQUENCEVERIFY\n // https://github.com/btcsuite/btcd/blob/master/txscript/opcode.go#L1174\n psbt.setVersion(TRANSACTION_VERSION);\n\n psbt.addInput({\n hash: tx.getHash(),\n index: outputIndex,\n tapInternalKey: internalPubkey,\n witnessUtxo: {\n value: tx.outs[outputIndex].value,\n script: tx.outs[outputIndex].script,\n },\n tapLeafScript: [tapLeafScript],\n sequence: timelock,\n });\n\n const estimatedFee = getWithdrawTxFee(feeRate);\n const outputValue = tx.outs[outputIndex].value - estimatedFee;\n if (outputValue < 0) {\n throw new Error(\n \"Not enough funds to cover the fee for withdrawal transaction\",\n );\n }\n if (outputValue < BTC_DUST_SAT) {\n throw new Error(\"Output value is less than dust limit\");\n }\n psbt.addOutput({\n address: withdrawalAddress,\n value: outputValue,\n });\n\n // Withdraw transaction has no time-based restrictions and can be included \n // in the next block immediately.\n psbt.setLocktime(0);\n\n return {\n psbt,\n fee: estimatedFee,\n };\n}\n\n/**\n * Constructs a slashing transaction for a staking output without prior unbonding.\n *\n * This transaction spends the staking output of the staking transaction and distributes the funds\n * according to the specified slashing rate.\n *\n * Outputs:\n * - The first output sends `input * slashing_rate` funds to the slashing address.\n * - The second output sends `input * (1 - slashing_rate) - fee` funds back to the user's address.\n *\n * Inputs:\n * - scripts: Scripts used to construct the taproot output.\n * - slashingScript: Script for the slashing condition.\n * - timelockScript: Script for the timelock condition.\n * - unbondingScript: Script for the unbonding condition.\n * - unbondingTimelockScript: Script for the unbonding timelock condition.\n * - transaction: The original staking transaction.\n * - slashingAddress: The address to send the slashed funds to.\n * - slashingRate: The rate at which the funds are slashed (0 < slashingRate < 1).\n * - minimumFee: The minimum fee for the transaction in satoshis.\n * - network: The Bitcoin network.\n * - outputIndex: The index of the output to be spent in the original transaction (default is 0).\n *\n * @param {Object} scripts - The scripts used in the transaction.\n * @param {Transaction} stakingTransaction - The original staking transaction.\n * @param {string} slashingPkScriptHex - The public key script to send the slashed funds to.\n * @param {number} slashingRate - The rate at which the funds are slashed.\n * @param {number} minimumFee - The minimum fee for the transaction in satoshis.\n * @param {networks.Network} network - The Bitcoin network.\n * @param {number} [outputIndex=0] - The index of the output to be spent in the original transaction.\n * @returns {{ psbt: Psbt }} An object containing the partially signed transaction (PSBT).\n */\nexport function slashTimelockUnbondedTransaction(\n scripts: {\n slashingScript: Buffer;\n timelockScript: Buffer;\n unbondingScript: Buffer;\n unbondingTimelockScript: Buffer;\n },\n stakingTransaction: Transaction,\n slashingPkScriptHex: string,\n slashingRate: number,\n minimumFee: number,\n network: networks.Network,\n outputIndex: number = 0,\n): { psbt: Psbt } {\n const slashingScriptTree: Taptree = [\n {\n output: scripts.slashingScript,\n },\n [{ output: scripts.unbondingScript }, { output: scripts.timelockScript }],\n ];\n return slashingTransaction(\n {\n unbondingTimelockScript: scripts.unbondingTimelockScript,\n slashingScript: scripts.slashingScript,\n },\n slashingScriptTree,\n stakingTransaction,\n slashingPkScriptHex,\n slashingRate,\n minimumFee,\n network,\n outputIndex,\n );\n}\n\n/**\n * Constructs a slashing transaction for an early unbonded transaction.\n *\n * This transaction spends the staking output of the staking transaction and distributes the funds\n * according to the specified slashing rate.\n *\n * Transaction outputs:\n * - The first output sends `input * slashing_rate` funds to the slashing address.\n * - The second output sends `input * (1 - slashing_rate) - fee` funds back to the user's address.\n *\n * @param {Object} scripts - The scripts used in the transaction. e.g slashingScript, unbondingTimelockScript\n * @param {Transaction} unbondingTx - The unbonding transaction.\n * @param {string} slashingPkScriptHex - The public key script to send the slashed funds to.\n * @param {number} slashingRate - The rate at which the funds are slashed.\n * @param {number} minimumSlashingFee - The minimum fee for the transaction in satoshis.\n * @param {networks.Network} network - The Bitcoin network.\n * @returns {{ psbt: Psbt }} An object containing the partially signed transaction (PSBT).\n */\nexport function slashEarlyUnbondedTransaction(\n scripts: {\n slashingScript: Buffer;\n unbondingTimelockScript: Buffer;\n },\n unbondingTx: Transaction,\n slashingPkScriptHex: string,\n slashingRate: number,\n minimumSlashingFee: number,\n network: networks.Network,\n): { psbt: Psbt } {\n const unbondingScriptTree: Taptree = [\n {\n output: scripts.slashingScript,\n },\n {\n output: scripts.unbondingTimelockScript,\n },\n ];\n return slashingTransaction(\n {\n unbondingTimelockScript: scripts.unbondingTimelockScript,\n slashingScript: scripts.slashingScript,\n },\n unbondingScriptTree,\n unbondingTx,\n slashingPkScriptHex,\n slashingRate,\n minimumSlashingFee,\n network,\n 0, // unbonding always has a single output\n );\n}\n\n/**\n * Constructs a slashing transaction for an on-demand unbonding.\n *\n * This transaction spends the staking output of the staking transaction and distributes the funds\n * according to the specified slashing rate.\n *\n * Transaction outputs:\n * - The first output sends `input * slashing_rate` funds to the slashing address.\n * - The second output sends `input * (1 - slashing_rate) - fee` funds back to the user's address.\n *\n * @param {Object} scripts - The scripts used in the transaction. e.g slashingScript, unbondingTimelockScript\n * @param {Transaction} transaction - The original staking/unbonding transaction.\n * @param {string} slashingPkScriptHex - The public key script to send the slashed funds to.\n * @param {number} slashingRate - The rate at which the funds are slashed. Two decimal places, otherwise it will be rounded down.\n * @param {number} minimumFee - The minimum fee for the transaction in satoshis.\n * @param {networks.Network} network - The Bitcoin network.\n * @param {number} [outputIndex=0] - The index of the output to be spent in the original transaction.\n * @returns {{ psbt: Psbt }} An object containing the partially signed transaction (PSBT).\n */\nfunction slashingTransaction(\n scripts: {\n unbondingTimelockScript: Buffer;\n slashingScript: Buffer;\n },\n scriptTree: Taptree,\n transaction: Transaction,\n slashingPkScriptHex: string,\n slashingRate: number,\n minimumFee: number,\n network: networks.Network,\n outputIndex: number = 0,\n): {\n psbt: Psbt;\n} {\n // Check that slashing rate and minimum fee are bigger than 0\n if (slashingRate <= 0 || slashingRate >= 1) {\n throw new Error(\"Slashing rate must be between 0 and 1\");\n }\n // Round the slashing rate to two decimal places\n slashingRate = parseFloat(slashingRate.toFixed(BTC_SLASHING_FRACTION_DIGITS));\n // Minimum fee must be a postive integer\n if (minimumFee <= 0 || !Number.isInteger(minimumFee)) {\n throw new Error(\"Minimum fee must be a positve integer\");\n }\n\n // Check that outputIndex is bigger or equal to 0\n if (outputIndex < 0 || !Number.isInteger(outputIndex)) {\n throw new Error(\"Output index must be an integer bigger or equal to 0\");\n }\n\n // Check that outputIndex is within the bounds of the transaction\n if (!transaction.outs[outputIndex]) {\n throw new Error(\"Output index is out of range\");\n }\n\n const redeem = {\n output: scripts.slashingScript,\n redeemVersion: REDEEM_VERSION,\n };\n\n const p2tr = payments.p2tr({\n internalPubkey,\n scriptTree,\n redeem,\n network,\n });\n\n const tapLeafScript = {\n leafVersion: redeem.redeemVersion,\n script: redeem.output,\n controlBlock: p2tr.witness![p2tr.witness!.length - 1],\n };\n\n const stakingAmount = transaction.outs[outputIndex].value;\n // Slashing rate is a percentage of the staking amount, rounded down to\n // the nearest integer to avoid sending decimal satoshis\n const slashingAmount = Math.round(stakingAmount * slashingRate);\n\n // Compute the slashing output\n const slashingOutput = Buffer.from(slashingPkScriptHex, \"hex\");\n\n // If OP_RETURN is not included, the slashing amount must be greater than the\n // dust limit.\n if (opcodes.OP_RETURN != slashingOutput[0]) {\n if (slashingAmount <= BTC_DUST_SAT) {\n throw new Error(\"Slashing amount is less than dust limit\");\n } \n }\n\n const userFunds = stakingAmount - slashingAmount - minimumFee;\n if (userFunds <= BTC_DUST_SAT) {\n throw new Error(\"User funds are less than dust limit\");\n }\n \n const psbt = new Psbt({ network });\n psbt.setVersion(TRANSACTION_VERSION);\n\n psbt.addInput({\n hash: transaction.getHash(),\n index: outputIndex,\n tapInternalKey: internalPubkey,\n witnessUtxo: {\n value: stakingAmount,\n script: transaction.outs[outputIndex].script,\n },\n tapLeafScript: [tapLeafScript],\n // not RBF-able\n sequence: NON_RBF_SEQUENCE,\n });\n\n // Add the slashing output\n psbt.addOutput({\n script: slashingOutput,\n value: slashingAmount,\n });\n\n // Change output contains unbonding timelock script\n const changeOutput = payments.p2tr({\n internalPubkey,\n scriptTree: { output: scripts.unbondingTimelockScript },\n network,\n });\n // Add the change output\n psbt.addOutput({\n address: changeOutput.address!,\n value: userFunds,\n });\n\n // Slashing transaction has no time-based restrictions and can be included \n // in the next block immediately.\n psbt.setLocktime(0);\n\n return { psbt };\n}\n\nexport function unbondingTransaction(\n scripts: {\n unbondingTimelockScript: Buffer;\n slashingScript: Buffer;\n },\n stakingTx: Transaction,\n unbondingFee: number,\n network: networks.Network,\n outputIndex: number = 0,\n): TransactionResult {\n // Check that transaction fee is bigger than 0\n if (unbondingFee <= 0) {\n throw new Error(\"Unbonding fee must be bigger than 0\");\n }\n\n // Check that outputIndex is bigger or equal to 0\n if (outputIndex < 0) {\n throw new Error(\"Output index must be bigger or equal to 0\");\n }\n\n const tx = new Transaction();\n tx.version = TRANSACTION_VERSION;\n\n tx.addInput(\n stakingTx.getHash(),\n outputIndex,\n NON_RBF_SEQUENCE, // not RBF-able\n );\n\n const unbondingOutputInfo = deriveUnbondingOutputInfo(scripts, network);\n\n const outputValue = stakingTx.outs[outputIndex].value - unbondingFee;\n if (outputValue < BTC_DUST_SAT) {\n throw new Error(\"Output value is less than dust limit for unbonding transaction\");\n }\n // Add the unbonding output\n if (!unbondingOutputInfo.outputAddress) {\n throw new Error(\"Unbonding output address is not defined\");\n }\n tx.addOutput(\n unbondingOutputInfo.scriptPubKey,\n outputValue,\n );\n\n // Unbonding transaction has no time-based restrictions and can be included \n // in the next block immediately.\n tx.locktime = 0;\n\n return {\n transaction: tx,\n fee: unbondingFee,\n };\n}\n\n// This function attaches covenant signatures as the transaction's witness\n// Note that the witness script expects exactly covenantQuorum number of signatures\n// to match the covenant parameters.\nexport const createCovenantWitness = (\n originalWitness: Buffer[],\n paramsCovenants: Buffer[],\n covenantSigs: CovenantSignature[],\n covenantQuorum: number,\n) => {\n if (covenantSigs.length < covenantQuorum) {\n throw new Error(\n `Not enough covenant signatures. Required: ${covenantQuorum}, `\n + `got: ${covenantSigs.length}`\n );\n }\n // Filter out the signatures that are not in the params covenants\n const filteredCovenantSigs = covenantSigs.filter((sig) => {\n const btcPkHexBuf = Buffer.from(sig.btcPkHex, \"hex\");\n return paramsCovenants.some(covenant => covenant.equals(btcPkHexBuf));\n });\n\n if (filteredCovenantSigs.length < covenantQuorum) {\n throw new Error(\n `Not enough valid covenant signatures. Required: ${covenantQuorum}, `\n + `got: ${filteredCovenantSigs.length}`\n );\n }\n\n // We only take exactly covenantQuorum number of signatures, even if more are provided.\n // Including extra signatures will cause the unbonding transaction to fail validation.\n // This is because the witness script expects exactly covenantQuorum number of signatures\n // to match the covenant parameters.\n const covenantSigsBuffers = covenantSigs\n .slice(0, covenantQuorum)\n .map((sig) => ({\n btcPkHex: Buffer.from(sig.btcPkHex, \"hex\"),\n sigHex: Buffer.from(sig.sigHex, \"hex\"),\n }));\n\n // we need covenant from params to be sorted in reverse order\n const paramsCovenantsSorted = [...paramsCovenants]\n .sort(Buffer.compare)\n .reverse();\n\n const composedCovenantSigs = paramsCovenantsSorted.map((covenant) => {\n // in case there's covenant with this btc_pk_hex we return the sig\n // otherwise we return empty Buffer\n const covenantSig = covenantSigsBuffers.find(\n (sig) => sig.btcPkHex.compare(covenant) === 0,\n );\n return covenantSig?.sigHex || Buffer.alloc(0);\n });\n\n return [...composedCovenantSigs, ...originalWitness];\n};\n", "export const BTC_DUST_SAT = 546;\n", "import { script as bitcoinScript } from \"bitcoinjs-lib\";\nimport { BTC_DUST_SAT } from \"../../constants/dustSat\";\nimport {\n LOW_RATE_ESTIMATION_ACCURACY_BUFFER,\n MAX_NON_LEGACY_OUTPUT_SIZE,\n OP_RETURN_OUTPUT_VALUE_SIZE,\n OP_RETURN_VALUE_SERIALIZE_SIZE,\n P2TR_INPUT_SIZE,\n P2TR_STAKING_EXPANSION_INPUT_SIZE,\n TX_BUFFER_SIZE_OVERHEAD,\n WALLET_RELAY_FEE_RATE_THRESHOLD,\n WITHDRAW_TX_BUFFER_SIZE,\n} from \"../../constants/fee\";\nimport { UTXO } from \"../../types/UTXO\";\nimport {\n TransactionOutput,\n} from \"../../types/psbtOutputs\";\nimport {\n getEstimatedChangeOutputSize,\n getInputSizeByScript,\n isOP_RETURN,\n} from \"./utils\";\n\n/**\n * Selects UTXOs and calculates the fee for a staking transaction.\n * This method selects the highest value UTXOs from all available UTXOs to\n * cover the staking amount and the transaction fees.\n * The formula used is:\n *\n * totalFee = (inputSize + outputSize) * feeRate + buffer\n * where outputSize may or may not include the change output size depending on the remaining value.\n *\n * @param availableUTXOs - All available UTXOs from the wallet.\n * @param stakingAmount - The amount to stake.\n * @param feeRate - The fee rate in satoshis per byte.\n * @param outputs - The outputs in the transaction.\n * @returns An object containing the selected UTXOs and the fee.\n * @throws Will throw an error if there are insufficient funds or if the fee cannot be calculated.\n */\nexport const getStakingTxInputUTXOsAndFees = (\n availableUTXOs: UTXO[],\n stakingAmount: number,\n feeRate: number,\n outputs: TransactionOutput[],\n): {\n selectedUTXOs: UTXO[];\n fee: number;\n} => {\n if (availableUTXOs.length === 0) {\n throw new Error(\"Insufficient funds\");\n }\n\n const validUTXOs = availableUTXOs.filter((utxo) => {\n const script = Buffer.from(utxo.scriptPubKey, \"hex\");\n return !!bitcoinScript.decompile(script);\n });\n\n if (validUTXOs.length === 0) {\n throw new Error(\"Insufficient funds: no valid UTXOs available for staking\");\n }\n\n // Sort available UTXOs from highest to lowest value\n const sortedUTXOs = validUTXOs.sort((a, b) => b.value - a.value);\n\n const selectedUTXOs: UTXO[] = [];\n let accumulatedValue = 0;\n let estimatedFee = 0;\n\n for (const utxo of sortedUTXOs) {\n selectedUTXOs.push(utxo);\n accumulatedValue += utxo.value;\n\n // Calculate the fee for the current set of UTXOs and outputs\n const estimatedSize = getEstimatedSize(selectedUTXOs, outputs);\n estimatedFee = estimatedSize * feeRate + rateBasedTxBufferFee(feeRate);\n // Check if there will be any change left after the staking amount and fee.\n // If there is, a change output needs to be added, which also comes with an additional fee.\n if (accumulatedValue - (stakingAmount + estimatedFee) > BTC_DUST_SAT) {\n estimatedFee += getEstimatedChangeOutputSize() * feeRate;\n }\n if (accumulatedValue >= stakingAmount + estimatedFee) {\n break;\n }\n }\n\n if (accumulatedValue < stakingAmount + estimatedFee) {\n throw new Error(\n \"Insufficient funds: unable to gather enough UTXOs to cover the staking amount and fees\",\n );\n }\n\n return {\n selectedUTXOs,\n fee: estimatedFee,\n };\n};\n\n/**\n * Calculates the required funding UTXO and fees for a staking expansion transaction.\n * \n * This function selects a single UTXO from available UTXOs to cover:\n * 1. Transaction fees for the expansion\n * 2. Any additional staking amount beyond the previous stake\n * \n * @param availableUTXOs - List of available UTXOs to choose from for funding\n * @param previousStakingTx - Details of the previous staking transaction being expanded\n * @param stakingAmount - Total staking amount for the expansion (includes previous + additional)\n * @param feeRate - Fee rate in satoshis per byte\n * @param outputs - Transaction outputs for the expansion\n * @returns Object containing the selected funding UTXO and calculated fee\n */\nexport const getStakingExpansionTxFundingUTXOAndFees = (\n availableUTXOs: UTXO[],\n feeRate: number,\n outputs: TransactionOutput[],\n): {\n selectedUTXO: UTXO;\n fee: number;\n} => {\n // Validate that we have UTXOs to work with\n if (availableUTXOs.length === 0) {\n throw new Error(\"Insufficient funds\");\n }\n\n // Filter out invalid UTXOs by checking if their script can be decompiled\n // This ensures we only work with properly formatted Bitcoin scripts\n const validUTXOs = availableUTXOs.filter((utxo) => {\n const script = Buffer.from(utxo.scriptPubKey, \"hex\");\n const decompiledScript = bitcoinScript.decompile(script);\n return decompiledScript && decompiledScript.length > 0;\n });\n\n if (validUTXOs.length === 0) {\n throw new Error(\"Insufficient funds: no valid UTXOs available for staking\");\n }\n\n // Sort available UTXOs from lowest to highest value for optimal selection\n // This helps us avoid selecting large UTXOs which can be used\n // for other activities.\n const sortedUTXOs = validUTXOs.sort((a, b) => a.value - b.value);\n\n // Iterate through UTXOs to find one that can cover the required fees\n for (const utxo of sortedUTXOs) {\n // Calculate the estimated transaction size including:\n // - Base transaction size (additional UTXOs + Outputs)\n // - Previous staking transaction output as the input for the expansion tx\n // Note: Staking transactions use P2TR (Taproot) format,\n // hence P2TR_STAKING_EXPANSION_INPUT_SIZE accounts for the witness size\n // including covenant signatures and is calibrated for a typical covenant\n // quorum of 6 signatures.\n const estimatedSize = getEstimatedSize(\n [utxo],\n outputs,\n ) + P2TR_STAKING_EXPANSION_INPUT_SIZE;\n \n // Calculate base fee: size * rate + buffer fee for network congestion\n let estimatedFee = estimatedSize * feeRate + rateBasedTxBufferFee(feeRate);\n \n // Check if this UTXO has enough value to cover the estimated fee\n // We are selecting a UTXO that can only cover the fee as\n // in the case of stake expansion we only want the additional UTXO to cover\n // the staking fee.\n // TODO: In the future, we will want to support selecting a UTXO for an increased\n // staking amount.\n if (utxo.value >= estimatedFee) {\n // Check if there will be change left after paying the fee\n // If change amount is above dust threshold, we need to add a change output\n // which increases the transaction size and fee\n if (utxo.value - estimatedFee > BTC_DUST_SAT) {\n // Add fee for the change output\n estimatedFee += getEstimatedChangeOutputSize() * feeRate;\n }\n // Finally, ensure the estimated fee is not greater than the UTXO value\n if (utxo.value >= estimatedFee) {\n return {\n selectedUTXO: utxo,\n fee: estimatedFee,\n };\n }\n // If the UTXO value is less than the estimated fee, we need to continue\n // searching for a UTXO that can cover the fees.\n }\n }\n \n // If no UTXO can cover the fees, throw an error\n throw new Error(\n \"Insufficient funds: unable to find a UTXO to cover the fees for the staking expansion transaction.\",\n );\n};\n\n\n/**\n * Calculates the estimated fee for a withdrawal transaction.\n * The fee calculation is based on estimated constants for input size,\n * output size, and additional overhead specific to withdrawal transactions.\n * Due to the slightly larger size of withdrawal transactions, an additional\n * buffer is included to account for this difference.\n *\n * @param feeRate - The fee rate in satoshis per vbyte.\n * @returns The estimated fee for a withdrawal transaction in satoshis.\n */\nexport const getWithdrawTxFee = (feeRate: number): number => {\n const inputSize = P2TR_INPUT_SIZE;\n const outputSize = getEstimatedChangeOutputSize();\n return (\n feeRate *\n (inputSize +\n outputSize +\n TX_BUFFER_SIZE_OVERHEAD +\n WITHDRAW_TX_BUFFER_SIZE) +\n rateBasedTxBufferFee(feeRate)\n );\n};\n\n\n/**\n * Calculates the estimated transaction size using a heuristic formula which\n * includes the input size, output size, and a fixexd buffer for the transaction size.\n * The formula used is:\n *\n * totalSize = inputSize + outputSize + TX_BUFFER_SIZE_OVERHEAD\n *\n * @param inputUtxos - The UTXOs used as inputs in the transaction.\n * @param outputs - The outputs in the transaction.\n * @returns The estimated transaction size in bytes.\n */\nconst getEstimatedSize = (\n inputUtxos: UTXO[],\n outputs: TransactionOutput[],\n): number => {\n // Estimate the input size\n const inputSize = inputUtxos.reduce((acc: number, u: UTXO): number => {\n const script = Buffer.from(u.scriptPubKey, \"hex\");\n const decompiledScript = bitcoinScript.decompile(script);\n if (!decompiledScript) {\n // Skip UTXOs with scripts that cannot be decompiled\n return acc;\n }\n return acc + getInputSizeByScript(script);\n }, 0);\n\n // Estimate the output size\n const outputSize = outputs.reduce((acc, output): number => {\n if (isOP_RETURN(output.scriptPubKey)) {\n return (\n acc +\n output.scriptPubKey.length +\n OP_RETURN_OUTPUT_VALUE_SIZE +\n OP_RETURN_VALUE_SERIALIZE_SIZE\n );\n }\n return acc + MAX_NON_LEGACY_OUTPUT_SIZE;\n }, 0);\n\n return inputSize + outputSize + TX_BUFFER_SIZE_OVERHEAD;\n};\n\n/**\n * Adds a buffer to the transaction size-based fee calculation if the fee rate is low.\n * Some wallets have a relayer fee requirement, which means if the fee rate is\n * less than or equal to WALLET_RELAY_FEE_RATE_THRESHOLD (2 satoshis per byte),\n * there is a risk that the fee might not be sufficient to get the transaction relayed.\n * To mitigate this risk, we add a buffer to the fee calculation to ensure that\n * the transaction can be relayed.\n *\n * If the fee rate is less than or equal to WALLET_RELAY_FEE_RATE_THRESHOLD, a fixed buffer is added\n * (LOW_RATE_ESTIMATION_ACCURACY_BUFFER). If the fee rate is higher, no buffer is added.\n *\n * @param feeRate - The fee rate in satoshis per byte.\n * @returns The buffer amount in satoshis to be added to the transaction fee.\n */\nconst rateBasedTxBufferFee = (feeRate: number): number => {\n return feeRate <= WALLET_RELAY_FEE_RATE_THRESHOLD\n ? LOW_RATE_ESTIMATION_ACCURACY_BUFFER\n : 0;\n};\n", "// Estimated size of a non-SegWit input in bytes\nexport const DEFAULT_INPUT_SIZE = 180;\n// Estimated size of a P2WPKH input in bytes\nexport const P2WPKH_INPUT_SIZE = 68;\n// Estimated size of a P2TR input in bytes. 42vb inputs + 16vb witness\nexport const P2TR_INPUT_SIZE = 58;\n// Estimated size of a P2TR input in bytes for staking expansion transactions.\n// This value accounts for the witness size including covenant signatures\n// and is calibrated for a typical covenant quorum of 6 signatures.\nexport const P2TR_STAKING_EXPANSION_INPUT_SIZE = 268;\n// Estimated size of a transaction buffer in bytes\nexport const TX_BUFFER_SIZE_OVERHEAD = 11;\n// Buffer for estimation accuracy when fee rate <= 2 sat/byte\nexport const LOW_RATE_ESTIMATION_ACCURACY_BUFFER = 30;\n// Size of a Taproot output, the largest non-legacy output type\nexport const MAX_NON_LEGACY_OUTPUT_SIZE = 43;\n// Buffer size for withdraw transaction fee calculation\nexport const WITHDRAW_TX_BUFFER_SIZE = 17;\n// Threshold for wallet relay fee rate. Different buffer fees are used based on this threshold\nexport const WALLET_RELAY_FEE_RATE_THRESHOLD = 2;\n// Estimated size of the OP_RETURN output value in bytes\nexport const OP_RETURN_OUTPUT_VALUE_SIZE = 8;\n// Because our OP_RETURN data will always be less than 80 bytes, which is less than 0xfd (253),\n// the value serialization size will always be 1 byte.\nexport const OP_RETURN_VALUE_SERIALIZE_SIZE = 1;\n", "import { script as bitcoinScript, opcodes, payments } from \"bitcoinjs-lib\";\nimport {\n DEFAULT_INPUT_SIZE,\n MAX_NON_LEGACY_OUTPUT_SIZE,\n P2TR_INPUT_SIZE,\n P2WPKH_INPUT_SIZE,\n} from \"../../constants/fee\";\nimport { UTXO } from \"../../types/UTXO\";\n\n// Helper function to check if a script is OP_RETURN\nexport const isOP_RETURN = (script: Buffer): boolean => {\n const decompiled = bitcoinScript.decompile(script);\n return !!decompiled && decompiled[0] === opcodes.OP_RETURN;\n};\n\n/**\n * Determines the size of a transaction input based on its script type.\n *\n * @param script - The script of the input.\n * @returns The estimated size of the input in bytes.\n */\nexport const getInputSizeByScript = (script: Buffer): number => {\n // Check if input is in the format of \"00 <20-byte public key hash>\"\n // If yes, it is a P2WPKH input\n try {\n const { address: p2wpkhAddress } = payments.p2wpkh({\n output: script,\n });\n if (p2wpkhAddress) {\n return P2WPKH_INPUT_SIZE;\n }\n // eslint-disable-next-line no-empty\n } catch (error) {} // Ignore errors\n // Check if input is in the format of \"51 <32-byte public key>\"\n // If yes, it is a P2TR input\n try {\n const { address: p2trAddress } = payments.p2tr({\n output: script,\n });\n if (p2trAddress) {\n return P2TR_INPUT_SIZE;\n }\n // eslint-disable-next-line no-empty\n } catch (error) {} // Ignore errors\n // Otherwise, assume the input is largest P2PKH address type\n return DEFAULT_INPUT_SIZE;\n};\n\n/**\n * Returns the estimated size for a change output.\n * This is used when the transaction has a change output to a particular address.\n *\n * @returns The estimated size for a change output in bytes.\n */\nexport const getEstimatedChangeOutputSize = (): number => {\n return MAX_NON_LEGACY_OUTPUT_SIZE;\n};\n\n/**\n * Returns the sum of the values of the UTXOs.\n *\n * @param inputUTXOs - The UTXOs to sum the values of.\n * @returns The sum of the values of the UTXOs in satoshis.\n */\nexport const inputValueSum = (inputUTXOs: UTXO[]): number => {\n return inputUTXOs.reduce((acc, utxo) => acc + utxo.value, 0);\n};\n", "// This sequence enables both the locktime field and also replace-by-fee\nexport const RBF_SEQUENCE = 0xfffffffd;\n// This sequence means the transaction is not replaceable\nexport const NON_RBF_SEQUENCE = 0xffffffff;\n// The Transaction version number used across the library(to be set in the psbt)\nexport const TRANSACTION_VERSION = 2;", "// minimum unbonding output value to avoid the unbonding output value being\n// less than Bitcoin dust\nexport const MIN_UNBONDING_OUTPUT_VALUE = 1000;", "import { fromBech32 } from \"@cosmjs/encoding\";\n\n/**\n * Validates a Babylon address. Babylon addresses are encoded in Bech32 format\n * and have a prefix of \"bbn\".\n * @param address - The address to validate.\n * @returns True if the address is valid, false otherwise.\n */\nexport const isValidBabylonAddress = (address: string): boolean => {\n try {\n const { prefix } = fromBech32(address);\n return prefix === \"bbn\";\n } catch (error) {\n return false;\n }\n};\n", "import { MIN_UNBONDING_OUTPUT_VALUE } from \"../../constants/unbonding\";\nimport { StakingError, StakingErrorCode } from \"../../error\";\nimport { StakingInputs, StakingParams, UTXO } from \"../../types\";\nimport { isValidBabylonAddress } from \"../babylon\";\nimport { isValidNoCoordPublicKey } from \"../btc\";\n\n/**\n * Validates the staking expansion input\n * @param babylonBtcTipHeight - The Babylon BTC tip height\n * @param inputUTXOs - The input UTXOs\n * @param stakingInput - The staking input\n * @param previousStakingInput - The previous staking input\n * @param babylonAddress - The Babylon address\n * @returns true if validation passes, throws error if validation fails\n */\nexport const validateStakingExpansionInputs = (\n {\n babylonBtcTipHeight,\n inputUTXOs,\n stakingInput,\n previousStakingInput,\n babylonAddress,\n }: {\n babylonBtcTipHeight?: number,\n inputUTXOs: UTXO[],\n stakingInput: StakingInputs,\n previousStakingInput: StakingInputs,\n babylonAddress?: string,\n }\n) => {\n if (babylonBtcTipHeight === 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Babylon BTC tip height cannot be 0\",\n );\n }\n if (!inputUTXOs || inputUTXOs.length === 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"No input UTXOs provided\",\n );\n }\n if (babylonAddress && !isValidBabylonAddress(babylonAddress)) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Invalid Babylon address\",\n );\n }\n\n // TODO: We currently don't support increasing the staking amount\n if (stakingInput.stakingAmountSat !== previousStakingInput.stakingAmountSat) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Staking expansion amount must equal the previous staking amount\",\n );\n }\n // Check the previous staking transaction's finality providers\n // are a subset of the new staking input's finality providers\n const currentFPs = stakingInput.finalityProviderPksNoCoordHex;\n const previousFPs = previousStakingInput.finalityProviderPksNoCoordHex;\n\n // Check if all previous finality providers are included in the current\n // staking\n const missingPreviousFPs = previousFPs.filter(prevFp => !currentFPs.includes(prevFp));\n \n if (missingPreviousFPs.length > 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n `Invalid staking expansion: all finality providers from the previous\n staking must be included. Missing: ${missingPreviousFPs.join(\", \")}`,\n );\n }\n}\n\n/**\n * Validate the staking transaction input data.\n *\n * @param {number} stakingAmountSat - The staking amount in satoshis.\n * @param {number} timelock - The staking time in blocks.\n * @param {StakingParams} params - The staking parameters.\n * @param {UTXO[]} inputUTXOs - The input UTXOs.\n * @param {number} feeRate - The Bitcoin fee rate in sat/vbyte\n * @throws {StakingError} - If the input data is invalid.\n */\nexport const validateStakingTxInputData = (\n stakingAmountSat: number,\n timelock: number,\n params: StakingParams,\n inputUTXOs: UTXO[],\n feeRate: number,\n) => {\n if (\n stakingAmountSat < params.minStakingAmountSat ||\n stakingAmountSat > params.maxStakingAmountSat\n ) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Invalid staking amount\",\n );\n }\n\n if (\n timelock < params.minStakingTimeBlocks ||\n timelock > params.maxStakingTimeBlocks\n ) {\n throw new StakingError(StakingErrorCode.INVALID_INPUT, \"Invalid timelock\");\n }\n\n if (inputUTXOs.length == 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"No input UTXOs provided\",\n );\n }\n if (feeRate <= 0) {\n throw new StakingError(StakingErrorCode.INVALID_INPUT, \"Invalid fee rate\");\n }\n};\n\n/**\n * Validate the staking parameters.\n * Extend this method to add additional validation for staking parameters based\n * on the staking type.\n * @param {StakingParams} params - The staking parameters.\n * @throws {StakingError} - If the parameters are invalid.\n */\nexport const validateParams = (params: StakingParams) => {\n // Check covenant public keys\n if (params.covenantNoCoordPks.length == 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Could not find any covenant public keys\",\n );\n }\n if (params.covenantNoCoordPks.length < params.covenantQuorum) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Covenant public keys must be greater than or equal to the quorum\",\n );\n }\n params.covenantNoCoordPks.forEach((pk) => {\n if (!isValidNoCoordPublicKey(pk)) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Covenant public key should contains no coordinate\",\n );\n }\n });\n // Check other parameters\n if (params.unbondingTime <= 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Unbonding time must be greater than 0\",\n );\n }\n if (params.unbondingFeeSat <= 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Unbonding fee must be greater than 0\",\n );\n }\n if (params.maxStakingAmountSat < params.minStakingAmountSat) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Max staking amount must be greater or equal to min staking amount\",\n );\n }\n if (\n params.minStakingAmountSat <\n params.unbondingFeeSat + MIN_UNBONDING_OUTPUT_VALUE\n ) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n `Min staking amount must be greater than unbonding fee plus ${MIN_UNBONDING_OUTPUT_VALUE}`,\n );\n }\n if (params.maxStakingTimeBlocks < params.minStakingTimeBlocks) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Max staking time must be greater or equal to min staking time\",\n );\n }\n if (params.minStakingTimeBlocks <= 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Min staking time must be greater than 0\",\n );\n }\n if (params.covenantQuorum <= 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Covenant quorum must be greater than 0\",\n );\n }\n if (params.slashing) {\n if (params.slashing.slashingRate <= 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Slashing rate must be greater than 0\",\n );\n }\n if (params.slashing.slashingRate > 1) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Slashing rate must be less or equal to 1\",\n );\n }\n if (params.slashing.slashingPkScriptHex.length == 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Slashing public key script is missing\",\n );\n }\n if (params.slashing.minSlashingTxFeeSat <= 0) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Minimum slashing transaction fee must be greater than 0\",\n );\n }\n }\n};\n\n/**\n * Validate the staking timelock.\n *\n * @param {number} stakingTimelock - The staking timelock.\n * @param {StakingParams} params - The staking parameters.\n * @throws {StakingError} - If the staking timelock is invalid.\n */\nexport const validateStakingTimelock = (\n stakingTimelock: number,\n params: StakingParams,\n) => {\n if (\n stakingTimelock < params.minStakingTimeBlocks ||\n stakingTimelock > params.maxStakingTimeBlocks\n ) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Staking transaction timelock is out of range\",\n );\n }\n};\n\n/**\n * Validate the staking expansion covenant quorum.\n * \n * The quorum is the number of covenant members that must be active in the\n * previous staking transaction in order to expand the staking.\n * \n * If the quorum is not met, the staking expansion will fail.\n *\n * @param {StakingParams} paramsForPreviousStakingTx - The staking parameters\n * for the previous staking transaction.\n * @param {StakingParams} paramsForCurrentStakingTx - The staking parameters\n * for the current staking transaction.\n * @throws {StakingError} - If the staking expansion covenant quorum is invalid.\n */\nexport const validateStakingExpansionCovenantQuorum = (\n paramsForPreviousStakingTx: StakingParams,\n paramsForCurrentStakingTx: StakingParams,\n) => {\n const previousCovenantMembers = paramsForPreviousStakingTx.covenantNoCoordPks;\n const currentCovenantMembers = paramsForCurrentStakingTx.covenantNoCoordPks;\n const requiredQuorum = paramsForPreviousStakingTx.covenantQuorum;\n\n // Count how many previous covenant members are still active\n const activePreviousMembers = previousCovenantMembers.filter(\n prevMember => currentCovenantMembers.includes(prevMember)\n ).length;\n\n if (activePreviousMembers < requiredQuorum) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n `Staking expansion failed: insufficient covenant quorum. ` +\n `Required: ${requiredQuorum}, Available: ${activePreviousMembers}. ` +\n `Too many covenant members have rotated out.`\n );\n }\n}", "import { networks, Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { StakingError, StakingErrorCode } from \"../error\";\nimport { StakingParams } from \"../types/params\";\nimport { PsbtResult, TransactionResult } from \"../types/transaction\";\nimport { UTXO } from \"../types/UTXO\";\nimport {\n isTaproot,\n isValidBitcoinAddress,\n isValidNoCoordPublicKey,\n} from \"../utils/btc\";\nimport {\n deriveSlashingOutput,\n deriveStakingOutputInfo,\n findMatchingTxOutputIndex,\n toBuffers,\n} from \"../utils/staking\";\nimport { stakingExpansionPsbt, stakingPsbt, unbondingPsbt } from \"./psbt\";\nimport { StakingScriptData, StakingScripts } from \"./stakingScript\";\nimport {\n stakingExpansionTransaction,\n slashEarlyUnbondedTransaction,\n slashTimelockUnbondedTransaction,\n stakingTransaction,\n unbondingTransaction,\n withdrawEarlyUnbondedTransaction,\n withdrawSlashingTransaction,\n withdrawTimelockUnbondedTransaction,\n} from \"./transactions\";\nimport { validateParams, validateStakingExpansionCovenantQuorum, validateStakingTimelock, validateStakingTxInputData } from \"../utils/staking/validation\";\nexport * from \"./stakingScript\";\n\nexport interface StakerInfo {\n address: string;\n publicKeyNoCoordHex: string;\n}\n\nexport class Staking {\n network: networks.Network;\n stakerInfo: StakerInfo;\n params: StakingParams;\n finalityProviderPksNoCoordHex: string[];\n stakingTimelock: number;\n\n constructor(\n network: networks.Network,\n stakerInfo: StakerInfo,\n params: StakingParams,\n finalityProviderPksNoCoordHex: string[],\n stakingTimelock: number,\n ) {\n // Perform validations\n if (!isValidBitcoinAddress(stakerInfo.address, network)) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Invalid staker bitcoin address\",\n );\n }\n if (!isValidNoCoordPublicKey(stakerInfo.publicKeyNoCoordHex)) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Invalid staker public key\",\n );\n }\n if (\n finalityProviderPksNoCoordHex.length === 0 || \n !finalityProviderPksNoCoordHex.every(isValidNoCoordPublicKey)\n ) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Invalid finality providers public keys\",\n );\n }\n validateParams(params);\n validateStakingTimelock(stakingTimelock, params);\n\n this.network = network;\n this.stakerInfo = stakerInfo;\n this.params = params;\n this.finalityProviderPksNoCoordHex = finalityProviderPksNoCoordHex;\n this.stakingTimelock = stakingTimelock;\n }\n\n /**\n * buildScripts builds the staking scripts for the staking transaction.\n * Note: different staking types may have different scripts.\n * e.g the observable staking script has a data embed script.\n *\n * @returns {StakingScripts} - The staking scripts.\n */\n buildScripts(): StakingScripts {\n const { covenantQuorum, covenantNoCoordPks, unbondingTime } = this.params;\n // Create staking script data\n let stakingScriptData;\n try {\n stakingScriptData = new StakingScriptData(\n Buffer.from(this.stakerInfo.publicKeyNoCoordHex, \"hex\"),\n this.finalityProviderPksNoCoordHex.map((pk) => Buffer.from(pk, \"hex\")),\n toBuffers(covenantNoCoordPks),\n covenantQuorum,\n this.stakingTimelock,\n unbondingTime,\n );\n } catch (error: unknown) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.SCRIPT_FAILURE,\n \"Cannot build staking script data\",\n );\n }\n\n // Build scripts\n let scripts;\n try {\n scripts = stakingScriptData.buildScripts();\n } catch (error: unknown) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.SCRIPT_FAILURE,\n \"Cannot build staking scripts\",\n );\n }\n return scripts;\n }\n\n /**\n * Create a staking transaction for staking.\n *\n * @param {number} stakingAmountSat - The amount to stake in satoshis.\n * @param {UTXO[]} inputUTXOs - The UTXOs to use as inputs for the staking\n * transaction.\n * @param {number} feeRate - The fee rate for the transaction in satoshis per byte.\n * @returns {TransactionResult} - An object containing the unsigned\n * transaction, and fee\n * @throws {StakingError} - If the transaction cannot be built\n */\n public createStakingTransaction(\n stakingAmountSat: number,\n inputUTXOs: UTXO[],\n feeRate: number,\n ): TransactionResult {\n validateStakingTxInputData(\n stakingAmountSat,\n this.stakingTimelock,\n this.params,\n inputUTXOs,\n feeRate,\n );\n\n const scripts = this.buildScripts();\n\n try {\n const { transaction, fee } = stakingTransaction(\n scripts,\n stakingAmountSat,\n this.stakerInfo.address,\n inputUTXOs,\n this.network,\n feeRate,\n );\n return {\n transaction,\n fee,\n };\n } catch (error: unknown) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build unsigned staking transaction\",\n );\n }\n }\n\n /**\n * Creates a staking expansion transaction that extends an existing BTC stake\n * to new finality providers or renews the timelock.\n * \n * This method implements RFC 037 BTC Stake Expansion,\n * allowing existing active BTC staking transactions\n * to extend their delegation to new finality providers without going through\n * the full unbonding process.\n * \n * The expansion transaction:\n * 1. Spends the previous staking transaction output as the first input\n * 2. Uses funding UTXO as additional input to cover transaction fees or\n * to increase the staking amount\n * 3. Creates a new staking output with expanded finality provider coverage or\n * renews the timelock\n * 4. Has an output returning the remaining funds as change (if any) to the\n * staker BTC address\n * \n * @param {number} stakingAmountSat - The total staking amount in satoshis\n * (The amount had to be equal to the previous staking amount for now, this\n * lib does not yet support increasing the staking amount at this stage)\n * @param {UTXO[]} inputUTXOs - Available UTXOs to use for funding the\n * expansion transaction fees. Only one will be selected for the expansion\n * @param {number} feeRate - Fee rate in satoshis per byte for the \n * expansion transaction\n * @param {StakingParams} paramsForPreviousStakingTx - Staking parameters \n * used in the previous staking transaction\n * @param {Object} previousStakingTxInfo - Necessary information to spend the\n * previous staking transaction.\n * @returns {TransactionResult & { fundingUTXO: UTXO }} - An object containing\n * the unsigned expansion transaction and calculated fee, and the funding UTXO\n * @throws {StakingError} - If the transaction cannot be built or validation\n * fails\n */\n public createStakingExpansionTransaction(\n stakingAmountSat: number,\n inputUTXOs: UTXO[],\n feeRate: number,\n paramsForPreviousStakingTx: StakingParams,\n previousStakingTxInfo: {\n stakingTx: Transaction,\n stakingInput: {\n finalityProviderPksNoCoordHex: string[],\n stakingTimelock: number,\n },\n },\n ): TransactionResult & {\n fundingUTXO: UTXO;\n } {\n validateStakingTxInputData(\n stakingAmountSat,\n this.stakingTimelock,\n this.params,\n inputUTXOs,\n feeRate,\n );\n validateStakingExpansionCovenantQuorum(\n paramsForPreviousStakingTx,\n this.params,\n );\n\n // Create a Staking instance for the previous staking transaction\n // This allows us to build the scripts needed to spend the previous\n // staking output\n const previousStaking = new Staking(\n this.network,\n this.stakerInfo,\n paramsForPreviousStakingTx,\n previousStakingTxInfo.stakingInput.finalityProviderPksNoCoordHex,\n previousStakingTxInfo.stakingInput.stakingTimelock,\n );\n \n // Build the expansion transaction using the stakingExpansionTransaction\n // utility function.\n // This creates a transaction that spends the previous staking output and\n // creates new staking outputs\n const {\n transaction: stakingExpansionTx,\n fee: stakingExpansionTxFee,\n fundingUTXO,\n } = stakingExpansionTransaction(\n this.network,\n this.buildScripts(),\n stakingAmountSat,\n this.stakerInfo.address,\n feeRate,\n inputUTXOs,\n {\n stakingTx: previousStakingTxInfo.stakingTx,\n scripts: previousStaking.buildScripts(),\n },\n )\n\n return {\n transaction: stakingExpansionTx,\n fee: stakingExpansionTxFee,\n fundingUTXO,\n };\n }\n\n /**\n * Create a staking psbt based on the existing staking transaction.\n *\n * @param {Transaction} stakingTx - The staking transaction.\n * @param {UTXO[]} inputUTXOs - The UTXOs to use as inputs for the staking\n * transaction. The UTXOs that were used to create the staking transaction should\n * be included in this array.\n * @returns {Psbt} - The psbt.\n */\n public toStakingPsbt(stakingTx: Transaction, inputUTXOs: UTXO[]): Psbt {\n // Check the staking output index can be found\n const scripts = this.buildScripts();\n const stakingOutputInfo = deriveStakingOutputInfo(scripts, this.network);\n findMatchingTxOutputIndex(\n stakingTx,\n stakingOutputInfo.outputAddress,\n this.network,\n );\n\n return stakingPsbt(\n stakingTx,\n this.network,\n inputUTXOs,\n isTaproot(this.stakerInfo.address, this.network)\n ? Buffer.from(this.stakerInfo.publicKeyNoCoordHex, \"hex\")\n : undefined,\n );\n }\n\n /**\n * Convert a staking expansion transaction to a PSBT.\n *\n * @param {Transaction} stakingExpansionTx - The staking expansion\n * transaction to convert\n * @param {UTXO[]} inputUTXOs - Available UTXOs for the\n * funding input (second input)\n * @param {StakingParams} paramsForPreviousStakingTx - Staking parameters\n * used for the previous staking transaction\n * @param {Object} previousStakingTxInfo - Information about the previous\n * staking transaction\n * @returns {Psbt} The PSBT for the staking expansion transaction\n * @throws {Error} If the previous staking output cannot be found or\n * validation fails\n */\n public toStakingExpansionPsbt(\n stakingExpansionTx: Transaction,\n inputUTXOs: UTXO[],\n paramsForPreviousStakingTx: StakingParams,\n previousStakingTxInfo: {\n stakingTx: Transaction,\n stakingInput: {\n finalityProviderPksNoCoordHex: string[],\n stakingTimelock: number,\n },\n },\n ): Psbt {\n // Reconstruct the previous staking instance to access its scripts and\n // parameters. This is necessary because we need to identify which output\n // in the previous staking transaction is the staking output (it could be\n // at any output index)\n const previousStaking = new Staking(\n this.network,\n this.stakerInfo,\n paramsForPreviousStakingTx,\n previousStakingTxInfo.stakingInput.finalityProviderPksNoCoordHex,\n previousStakingTxInfo.stakingInput.stakingTimelock,\n );\n\n // Find the staking output address in the previous staking transaction\n const previousScripts = previousStaking.buildScripts();\n const { outputAddress } = deriveStakingOutputInfo(previousScripts, this.network);\n \n // Find the output index in the previous staking transaction that matches\n // the staking output address.\n const previousStakingOutputIndex = findMatchingTxOutputIndex(\n previousStakingTxInfo.stakingTx,\n outputAddress,\n this.network,\n );\n\n // Create and return the PSBT for the staking expansion transaction\n // The PSBT will have two inputs:\n // 1. The previous staking output\n // 2. A funding UTXO from inputUTXOs (for additional funds)\n return stakingExpansionPsbt(\n this.network,\n stakingExpansionTx,\n {\n stakingTx: previousStakingTxInfo.stakingTx,\n outputIndex: previousStakingOutputIndex,\n },\n inputUTXOs,\n previousScripts,\n isTaproot(this.stakerInfo.address, this.network)\n ? Buffer.from(this.stakerInfo.publicKeyNoCoordHex, \"hex\")\n : undefined,\n );\n }\n\n /**\n * Create an unbonding transaction for staking.\n *\n * @param {Transaction} stakingTx - The staking transaction to unbond.\n * @returns {TransactionResult} - An object containing the unsigned\n * transaction, and fee\n * @throws {StakingError} - If the transaction cannot be built\n */\n public createUnbondingTransaction(stakingTx: Transaction): TransactionResult {\n // Build scripts\n const scripts = this.buildScripts();\n const { outputAddress } = deriveStakingOutputInfo(scripts, this.network);\n // Reconstruct the stakingOutputIndex\n const stakingOutputIndex = findMatchingTxOutputIndex(\n stakingTx,\n outputAddress,\n this.network,\n );\n // Create the unbonding transaction\n try {\n const { transaction } = unbondingTransaction(\n scripts,\n stakingTx,\n this.params.unbondingFeeSat,\n this.network,\n stakingOutputIndex,\n );\n return {\n transaction,\n fee: this.params.unbondingFeeSat,\n };\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build the unbonding transaction\",\n );\n }\n }\n\n /**\n * Create an unbonding psbt based on the existing unbonding transaction and\n * staking transaction.\n *\n * @param {Transaction} unbondingTx - The unbonding transaction.\n * @param {Transaction} stakingTx - The staking transaction.\n *\n * @returns {Psbt} - The psbt.\n */\n public toUnbondingPsbt(\n unbondingTx: Transaction,\n stakingTx: Transaction,\n ): Psbt {\n return unbondingPsbt(\n this.buildScripts(),\n unbondingTx,\n stakingTx,\n this.network,\n );\n }\n\n /**\n * Creates a withdrawal transaction that spends from an unbonding or slashing\n * transaction. The timelock on the input transaction must have expired before\n * this withdrawal can be valid.\n *\n * @param {Transaction} earlyUnbondedTx - The unbonding or slashing\n * transaction to withdraw from\n * @param {number} feeRate - Fee rate in satoshis per byte for the withdrawal\n * transaction\n * @returns {PsbtResult} - Contains the unsigned PSBT and fee amount\n * @throws {StakingError} - If the input transaction is invalid or withdrawal\n * transaction cannot be built\n */\n public createWithdrawEarlyUnbondedTransaction(\n earlyUnbondedTx: Transaction,\n feeRate: number,\n ): PsbtResult {\n // Build scripts\n const scripts = this.buildScripts();\n\n // Create the withdraw early unbonded transaction\n try {\n return withdrawEarlyUnbondedTransaction(\n scripts,\n earlyUnbondedTx,\n this.stakerInfo.address,\n this.network,\n feeRate,\n );\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build unsigned withdraw early unbonded transaction\",\n );\n }\n }\n\n /**\n * Create a withdrawal psbt that spends a naturally expired staking\n * transaction.\n *\n * @param {Transaction} stakingTx - The staking transaction to withdraw from.\n * @param {number} feeRate - The fee rate for the transaction in satoshis per byte.\n * @returns {PsbtResult} - An object containing the unsigned psbt and fee\n * @throws {StakingError} - If the delegation is invalid or the transaction cannot be built\n */\n public createWithdrawStakingExpiredPsbt(\n stakingTx: Transaction,\n feeRate: number,\n ): PsbtResult {\n // Build scripts\n const scripts = this.buildScripts();\n const { outputAddress } = deriveStakingOutputInfo(scripts, this.network);\n // Reconstruct the stakingOutputIndex\n const stakingOutputIndex = findMatchingTxOutputIndex(\n stakingTx,\n outputAddress,\n this.network,\n );\n\n // Create the timelock unbonded transaction\n try {\n return withdrawTimelockUnbondedTransaction(\n scripts,\n stakingTx,\n this.stakerInfo.address,\n this.network,\n feeRate,\n stakingOutputIndex,\n );\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build unsigned timelock unbonded transaction\",\n );\n }\n }\n\n /**\n * Create a slashing psbt spending from the staking output.\n *\n * @param {Transaction} stakingTx - The staking transaction to slash.\n * @returns {PsbtResult} - An object containing the unsigned psbt and fee\n * @throws {StakingError} - If the delegation is invalid or the transaction cannot be built\n */\n public createStakingOutputSlashingPsbt(stakingTx: Transaction): PsbtResult {\n if (!this.params.slashing) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Slashing parameters are missing\",\n );\n }\n\n // Build scripts\n const scripts = this.buildScripts();\n\n // Get the staking output address\n const { outputAddress } = deriveStakingOutputInfo(scripts, this.network);\n\n // Reconstruct the stakingOutputIndex\n const stakingOutputIndex = findMatchingTxOutputIndex(\n stakingTx,\n outputAddress,\n this.network,\n )\n\n // create the slash timelock unbonded transaction\n try {\n const { psbt } = slashTimelockUnbondedTransaction(\n scripts,\n stakingTx,\n this.params.slashing.slashingPkScriptHex,\n this.params.slashing.slashingRate,\n this.params.slashing.minSlashingTxFeeSat,\n this.network,\n stakingOutputIndex,\n );\n return {\n psbt,\n fee: this.params.slashing.minSlashingTxFeeSat,\n };\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build the slash timelock unbonded transaction\",\n );\n }\n }\n\n /**\n * Create a slashing psbt for an unbonding output.\n *\n * @param {Transaction} unbondingTx - The unbonding transaction to slash.\n * @returns {PsbtResult} - An object containing the unsigned psbt and fee\n * @throws {StakingError} - If the delegation is invalid or the transaction cannot be built\n */\n public createUnbondingOutputSlashingPsbt(\n unbondingTx: Transaction,\n ): PsbtResult {\n if (!this.params.slashing) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n \"Slashing parameters are missing\",\n );\n }\n // Build scripts\n const scripts = this.buildScripts();\n\n // create the slash timelock unbonded transaction\n try {\n const { psbt } = slashEarlyUnbondedTransaction(\n scripts,\n unbondingTx,\n this.params.slashing.slashingPkScriptHex,\n this.params.slashing.slashingRate,\n this.params.slashing.minSlashingTxFeeSat,\n this.network,\n );\n return {\n psbt,\n fee: this.params.slashing.minSlashingTxFeeSat,\n };\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build the slash early unbonded transaction\",\n );\n }\n }\n\n /**\n * Create a withdraw slashing psbt that spends a slashing transaction from the\n * staking output.\n *\n * @param {Transaction} slashingTx - The slashing transaction.\n * @param {number} feeRate - The fee rate for the transaction in satoshis per byte.\n * @returns {PsbtResult} - An object containing the unsigned psbt and fee\n * @throws {StakingError} - If the delegation is invalid or the transaction cannot be built\n */\n public createWithdrawSlashingPsbt(\n slashingTx: Transaction,\n feeRate: number,\n ): PsbtResult {\n // Build scripts\n const scripts = this.buildScripts();\n const slashingOutputInfo = deriveSlashingOutput(scripts, this.network);\n\n // Reconstruct and validate the slashingOutputIndex\n const slashingOutputIndex = findMatchingTxOutputIndex(\n slashingTx,\n slashingOutputInfo.outputAddress,\n this.network,\n );\n\n // Create the withdraw slashed transaction\n try {\n return withdrawSlashingTransaction(\n scripts,\n slashingTx,\n this.stakerInfo.address,\n this.network,\n feeRate,\n slashingOutputIndex,\n );\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build withdraw slashing transaction\",\n );\n }\n }\n}\n", "import { btccheckpoint, btcstaking, btcstakingtx } from '@babylonlabs-io/babylon-proto-ts';\nimport {\n BIP322Sig,\n BTCSigType,\n ProofOfPossessionBTC,\n} from '@babylonlabs-io/babylon-proto-ts/dist/generated/babylon/btcstaking/v1/pop';\nimport { Psbt, Transaction, networks } from 'bitcoinjs-lib';\nimport type { Emitter } from 'nanoevents';\n\nimport { StakerInfo, Staking } from '.';\nimport { BABYLON_REGISTRY_TYPE_URLS } from '../constants/registry';\nimport { StakingError, StakingErrorCode } from '../error';\nimport { TransactionResult, UTXO } from '../types';\nimport { ActionName } from '../types/action';\nimport { Contract, ContractId } from '../types/contract';\nimport { ManagerEvents } from '../types/events';\nimport { BabylonProvider, BtcProvider, InclusionProof, StakingInputs, UpgradeConfig } from '../types/manager';\nimport { StakingParams, VersionedStakingParams } from '../types/params';\nimport { reverseBuffer } from '../utils';\nimport { isValidBabylonAddress } from '../utils/babylon';\nimport { isNativeSegwit, isTaproot } from '../utils/btc';\nimport { buildPopMessage } from '../utils/pop';\nimport {\n clearTxSignatures,\n deriveMerkleProof,\n deriveStakingOutputInfo,\n extractFirstSchnorrSignatureFromTransaction,\n findMatchingTxOutputIndex,\n} from '../utils/staking';\nimport { getBabylonParamByBtcHeight, getBabylonParamByVersion } from '../utils/staking/param';\n\nimport { createCovenantWitness } from './transactions';\nimport { validateStakingExpansionInputs } from '../utils/staking/validation';\n\nexport class BabylonBtcStakingManager {\n private upgradeConfig?: UpgradeConfig;\n\n constructor(\n protected network: networks.Network,\n protected stakingParams: VersionedStakingParams[],\n protected btcProvider: BtcProvider,\n protected babylonProvider: BabylonProvider,\n protected ee?: Emitter<ManagerEvents>,\n upgradeConfig?: UpgradeConfig\n ) {\n this.network = network;\n\n if (stakingParams.length === 0) {\n throw new Error('No staking parameters provided');\n }\n this.stakingParams = stakingParams;\n\n this.upgradeConfig = upgradeConfig;\n }\n\n /**\n * Creates a signed Pre-Staking Registration transaction that is ready to be\n * sent to the Babylon chain.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param stakingInput - The staking inputs.\n * @param babylonBtcTipHeight - The Babylon BTC tip height.\n * @param inputUTXOs - The UTXOs that will be used to pay for the staking\n * transaction.\n * @param feeRate - The fee rate in satoshis per byte. Typical value for the\n * fee rate is above 1. If the fee rate is too low, the transaction will not\n * be included in a block.\n * @param babylonAddress - The Babylon bech32 encoded address of the staker.\n * @returns The signed babylon pre-staking registration transaction in base64\n * format.\n */\n async preStakeRegistrationBabylonTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n babylonBtcTipHeight: number,\n inputUTXOs: UTXO[],\n feeRate: number,\n babylonAddress: string\n ): Promise<{\n signedBabylonTx: Uint8Array;\n stakingTx: Transaction;\n }> {\n if (babylonBtcTipHeight === 0) {\n throw new Error('Babylon BTC tip height cannot be 0');\n }\n if (inputUTXOs.length === 0) {\n throw new Error('No input UTXOs provided');\n }\n if (!isValidBabylonAddress(babylonAddress)) {\n throw new Error('Invalid Babylon address');\n }\n\n // Get the Babylon params based on the BTC tip height from Babylon chain\n const params = getBabylonParamByBtcHeight(babylonBtcTipHeight, this.stakingParams);\n\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n // Create unsigned staking transaction\n const { transaction } = staking.createStakingTransaction(stakingInput.stakingAmountSat, inputUTXOs, feeRate);\n\n // Create delegation message without including inclusion proof\n const msg = await this.createBtcDelegationMsg(\n 'delegation:create',\n staking,\n stakingInput,\n transaction,\n babylonAddress,\n stakerBtcInfo,\n params\n );\n\n this.ee?.emit('delegation:create', {\n type: 'create-btc-delegation-msg',\n });\n\n return {\n signedBabylonTx: await this.babylonProvider.signTransaction(msg),\n stakingTx: transaction,\n };\n }\n\n /**\n * Create a signed staking expansion transaction that is ready to be sent to\n * the Babylon chain.\n */\n async stakingExpansionRegistrationBabylonTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n babylonBtcTipHeight: number,\n inputUTXOs: UTXO[],\n feeRate: number,\n babylonAddress: string,\n // Previous staking transaction info\n previousStakingTxInfo: {\n stakingTx: Transaction;\n paramVersion: number;\n stakingInput: StakingInputs;\n }\n ): Promise<{\n signedBabylonTx: Uint8Array;\n stakingTx: Transaction;\n }> {\n // Perform validation for the staking expansion inputs\n validateStakingExpansionInputs({\n babylonBtcTipHeight,\n inputUTXOs,\n stakingInput,\n previousStakingInput: previousStakingTxInfo.stakingInput,\n babylonAddress,\n });\n // Param for the expandsion staking transaction\n const params = getBabylonParamByBtcHeight(babylonBtcTipHeight, this.stakingParams);\n\n const paramsForPreviousStakingTx = getBabylonParamByVersion(previousStakingTxInfo.paramVersion, this.stakingParams);\n\n const stakingInstance = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const { transaction: stakingExpansionTx, fundingUTXO } = stakingInstance.createStakingExpansionTransaction(\n stakingInput.stakingAmountSat,\n inputUTXOs,\n feeRate,\n paramsForPreviousStakingTx,\n previousStakingTxInfo\n );\n let fundingTx;\n try {\n fundingTx = await this.btcProvider.getTransactionHex(fundingUTXO.txid);\n } catch (error) {\n throw StakingError.fromUnknown(\n error,\n StakingErrorCode.INVALID_INPUT,\n 'Failed to retrieve funding transaction hex'\n );\n }\n\n // Create delegation message without including inclusion proof\n const msg = await this.createBtcDelegationMsg(\n 'delegation:expand',\n stakingInstance,\n stakingInput,\n stakingExpansionTx,\n babylonAddress,\n stakerBtcInfo,\n params,\n {\n delegationExpansionInfo: {\n previousStakingTx: previousStakingTxInfo.stakingTx,\n fundingTx: Transaction.fromHex(fundingTx),\n },\n }\n );\n\n this.ee?.emit('delegation:expand', {\n type: 'create-btc-delegation-msg',\n });\n\n return {\n signedBabylonTx: await this.babylonProvider.signTransaction(msg),\n stakingTx: stakingExpansionTx,\n };\n }\n\n /**\n * Estimates the transaction fee for a BTC staking expansion transaction.\n *\n * @param {StakerInfo} stakerBtcInfo - The staker's Bitcoin information\n * including address and public key\n * @param {number} babylonBtcTipHeight - The current Babylon BTC tip height\n * used to determine staking parameters\n * @param {StakingInputs} stakingInput - The new staking input parameters for\n * the expansion\n * @param {UTXO[]} inputUTXOs - Available UTXOs that can be used for funding\n * the expansion transaction\n * @param {number} feeRate - Fee rate in satoshis per byte for the expansion\n * transaction\n * @param {Object} previousStakingTxInfo - Information about the previous\n * staking transaction being expanded\n * @returns {number} - The estimated transaction fee in satoshis\n * @throws {Error} - If validation fails or the fee cannot be calculated\n */\n estimateBtcStakingExpansionFee(\n stakerBtcInfo: StakerInfo,\n babylonBtcTipHeight: number,\n stakingInput: StakingInputs,\n inputUTXOs: UTXO[],\n feeRate: number,\n previousStakingTxInfo: {\n stakingTx: Transaction;\n paramVersion: number;\n stakingInput: StakingInputs;\n }\n ): number {\n // Validate all input parameters before fee calculation\n validateStakingExpansionInputs({\n babylonBtcTipHeight,\n inputUTXOs,\n stakingInput,\n previousStakingInput: previousStakingTxInfo.stakingInput,\n });\n\n // Get the appropriate staking parameters based on the current Babylon BTC\n // tip height. This ensures we use the correct parameters for the current\n // network state\n const params = getBabylonParamByBtcHeight(babylonBtcTipHeight, this.stakingParams);\n\n // Get the staking parameters that were used in the previous staking\n // transaction. This is needed to properly reconstruct the previous staking\n // scripts\n const paramsForPreviousStakingTx = getBabylonParamByVersion(previousStakingTxInfo.paramVersion, this.stakingParams);\n\n // Create a Staking instance for the new expansion with current parameters\n // This will be used to build the new staking scripts and calculate the\n // transaction\n const stakingInstance = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n const { fee } = stakingInstance.createStakingExpansionTransaction(\n stakingInput.stakingAmountSat,\n inputUTXOs,\n feeRate,\n paramsForPreviousStakingTx,\n previousStakingTxInfo\n );\n\n return fee;\n }\n\n /**\n * Creates a signed post-staking registration transaction that is ready to be\n * sent to the Babylon chain. This is used when a staking transaction is\n * already created and included in a BTC block and we want to register it on\n * the Babylon chain.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param stakingTx - The staking transaction.\n * @param stakingTxHeight - The BTC height in which the staking transaction\n * is included.\n * @param stakingInput - The staking inputs.\n * @param inclusionProof - Merkle Proof of Inclusion: Verifies transaction\n * inclusion in a Bitcoin block that is k-deep.\n * @param babylonAddress - The Babylon bech32 encoded address of the staker.\n * @returns The signed babylon transaction in base64 format.\n */\n async postStakeRegistrationBabylonTransaction(\n stakerBtcInfo: StakerInfo,\n stakingTx: Transaction,\n stakingTxHeight: number,\n stakingInput: StakingInputs,\n inclusionProof: InclusionProof,\n babylonAddress: string\n ): Promise<{\n signedBabylonTx: Uint8Array;\n }> {\n // Get the Babylon params at the time of the staking transaction\n const params = getBabylonParamByBtcHeight(stakingTxHeight, this.stakingParams);\n\n if (!isValidBabylonAddress(babylonAddress)) {\n throw new Error('Invalid Babylon address');\n }\n\n const stakingInstance = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n // Validate if the stakingTx is valid based on the retrieved Babylon param\n const scripts = stakingInstance.buildScripts();\n const stakingOutputInfo = deriveStakingOutputInfo(scripts, this.network);\n // Error will be thrown if the expected staking output address is not found\n // in the stakingTx\n findMatchingTxOutputIndex(stakingTx, stakingOutputInfo.outputAddress, this.network);\n\n // Create delegation message\n const delegationMsg = await this.createBtcDelegationMsg(\n 'delegation:register',\n stakingInstance,\n stakingInput,\n stakingTx,\n babylonAddress,\n stakerBtcInfo,\n params,\n {\n inclusionProof: this.getInclusionProof(inclusionProof),\n }\n );\n\n this.ee?.emit('delegation:register', {\n type: 'create-btc-delegation-msg',\n });\n\n return {\n signedBabylonTx: await this.babylonProvider.signTransaction(delegationMsg),\n };\n }\n\n /**\n * Estimates the BTC fee required for staking.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param babylonBtcTipHeight - The BTC tip height recorded on the Babylon\n * chain.\n * @param stakingInput - The staking inputs.\n * @param inputUTXOs - The UTXOs that will be used to pay for the staking\n * transaction.\n * @param feeRate - The fee rate in satoshis per byte. Typical value for the\n * fee rate is above 1. If the fee rate is too low, the transaction will not\n * be included in a block.\n * @returns The estimated BTC fee in satoshis.\n */\n estimateBtcStakingFee(\n stakerBtcInfo: StakerInfo,\n babylonBtcTipHeight: number,\n stakingInput: StakingInputs,\n inputUTXOs: UTXO[],\n feeRate: number\n ): number {\n if (babylonBtcTipHeight === 0) {\n throw new Error('Babylon BTC tip height cannot be 0');\n }\n // Get the param based on the tip height\n const params = getBabylonParamByBtcHeight(babylonBtcTipHeight, this.stakingParams);\n\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const { fee: stakingFee } = staking.createStakingTransaction(stakingInput.stakingAmountSat, inputUTXOs, feeRate);\n\n return stakingFee;\n }\n\n /**\n * Creates a signed staking transaction that is ready to be sent to the BTC\n * network.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param stakingInput - The staking inputs.\n * @param unsignedStakingTx - The unsigned staking transaction.\n * @param inputUTXOs - The UTXOs that will be used to pay for the staking\n * transaction.\n * @param stakingParamsVersion - The params version that was used to create the\n * delegation in Babylon chain\n * @returns The signed staking transaction.\n */\n async createSignedBtcStakingTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n unsignedStakingTx: Transaction,\n inputUTXOs: UTXO[],\n stakingParamsVersion: number\n ): Promise<Transaction> {\n const params = getBabylonParamByVersion(stakingParamsVersion, this.stakingParams);\n\n if (inputUTXOs.length === 0) {\n throw new Error('No input UTXOs provided');\n }\n\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const stakingPsbt = staking.toStakingPsbt(unsignedStakingTx, inputUTXOs);\n\n const contracts: Contract[] = [\n {\n id: ContractId.STAKING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n minUnbondingTime: params.unbondingTime,\n stakingDuration: stakingInput.stakingTimelock,\n },\n },\n ];\n\n this.ee?.emit('delegation:stake', {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n unbondingTimeBlocks: params.unbondingTime,\n stakingDuration: stakingInput.stakingTimelock,\n type: 'staking',\n });\n\n const signedStakingPsbtHex = await this.btcProvider.signPsbt(stakingPsbt.toHex(), {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_STAKING_TRANSACTION,\n },\n });\n\n return Psbt.fromHex(signedStakingPsbtHex).extractTransaction();\n }\n\n /**\n * Creates a signed staking expansion transaction that is ready to be sent to\n * the BTC network.\n *\n * @param {StakerInfo} stakerBtcInfo - The staker's BTC information including\n * address and public key\n * @param {StakingInputs} stakingInput - The staking inputs for the expansion\n * @param {Transaction} unsignedStakingExpansionTx - The unsigned staking\n * expansion transaction\n * @param {UTXO[]} inputUTXOs - Available UTXOs for the funding input\n * @param {number} stakingParamsVersion - The version of staking parameters\n * that was used when registering the staking expansion delegation.\n * @param {Object} previousStakingTxInfo - Information about the previous\n * staking transaction\n * @param {Array} covenantStakingExpansionSignatures - Covenant committee\n * signatures for the expansion\n * @returns {Promise<Transaction>} The fully signed staking expansion\n * transaction\n * @throws {Error} If signing fails, validation fails, or required data is\n * missing\n */\n async createSignedBtcStakingExpansionTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n unsignedStakingExpansionTx: Transaction,\n inputUTXOs: UTXO[],\n stakingParamsVersion: number,\n previousStakingTxInfo: {\n stakingTx: Transaction;\n paramVersion: number;\n stakingInput: StakingInputs;\n },\n covenantStakingExpansionSignatures: {\n btcPkHex: string;\n sigHex: string;\n }[]\n ): Promise<Transaction> {\n validateStakingExpansionInputs({\n inputUTXOs,\n stakingInput,\n previousStakingInput: previousStakingTxInfo.stakingInput,\n });\n\n // Get the staking parameters for the current version\n // These parameters define the covenant committee and other staking rules\n const params = getBabylonParamByVersion(stakingParamsVersion, this.stakingParams);\n\n // Validate that input UTXOs are provided for the funding input\n if (inputUTXOs.length === 0) {\n throw new Error('No input UTXOs provided');\n }\n\n // Create a new staking instance with the current parameters\n // This will be used to build the PSBT for the expansion transaction\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const previousParams = getBabylonParamByVersion(previousStakingTxInfo.paramVersion, this.stakingParams);\n\n // Create the PSBT for the staking expansion transaction\n // This PSBT will have two inputs: the previous staking output and a\n // funding UTXO\n const stakingExpansionPsbt = staking.toStakingExpansionPsbt(\n unsignedStakingExpansionTx,\n inputUTXOs,\n previousParams,\n previousStakingTxInfo\n );\n\n // Define the contract information for the PSBT signing\n const contracts: Contract[] = [\n {\n id: ContractId.STAKING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n minUnbondingTime: params.unbondingTime,\n stakingDuration: stakingInput.stakingTimelock,\n },\n },\n ];\n\n // Emit an event to notify listeners about the staking expansion\n // This can be used for logging, monitoring, or UI updates\n this.ee?.emit('delegation:stake', {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n unbondingTimeBlocks: params.unbondingTime,\n stakingDuration: stakingInput.stakingTimelock,\n type: 'staking',\n });\n\n // Sign the PSBT using the BTC provider (wallet)\n // The wallet will sign the transaction based on the contract information\n // provided\n const signedStakingPsbtHex = await this.btcProvider.signPsbt(stakingExpansionPsbt.toHex(), {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_STAKING_TRANSACTION,\n },\n });\n\n // Extract the signed transaction from the PSBT\n const signedStakingExpansionTx = Psbt.fromHex(signedStakingPsbtHex).extractTransaction();\n\n // Validate that the signed transaction hash matches the unsigned\n // transaction hash\n // This ensures that the signing process didn't change the transaction\n // structure\n if (signedStakingExpansionTx.getId() !== unsignedStakingExpansionTx.getId()) {\n throw new Error('Staking expansion transaction hash does not match the computed hash');\n }\n\n // Add covenant committee signatures to the transaction\n // Convert covenant public keys from hex strings to buffers\n // The covenants committee is based on the params at the time of the previous\n // staking transaction. Hence using the previous params here.\n const covenantBuffers = previousParams.covenantNoCoordPks.map((covenant) => Buffer.from(covenant, 'hex'));\n\n // Create the witness that includes both the staker's signature and covenant\n // signatures\n // The witness is the data that proves the transaction is authorized\n const witness = createCovenantWitness(\n // The first input of the staking expansion transaction is the previous\n // staking output. We will attach the covenant signatures to this input\n // to unbond the previousstaking output.\n signedStakingExpansionTx.ins[0].witness,\n covenantBuffers,\n covenantStakingExpansionSignatures,\n previousParams.covenantQuorum\n );\n\n // Overwrite the witness to include the covenant staking expansion signatures\n // This makes the transaction valid for submission to the Bitcoin network\n signedStakingExpansionTx.ins[0].witness = witness;\n\n return signedStakingExpansionTx;\n }\n\n /**\n * Creates a partial signed unbonding transaction that is only signed by the\n * staker. In order to complete the unbonding transaction, the covenant\n * unbonding signatures need to be added to the transaction before sending it\n * to the BTC network.\n * NOTE: This method should only be used for Babylon phase-1 unbonding.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param stakingInput - The staking inputs.\n * @param stakingParamsVersion - The params version that was used to create the\n * delegation in Babylon chain\n * @param stakingTx - The staking transaction.\n * @returns The partial signed unbonding transaction and its fee.\n */\n async createPartialSignedBtcUnbondingTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n stakingParamsVersion: number,\n stakingTx: Transaction\n ): Promise<TransactionResult> {\n // Get the staking params at the time of the staking transaction\n const params = getBabylonParamByVersion(stakingParamsVersion, this.stakingParams);\n\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const { transaction: unbondingTx, fee } = staking.createUnbondingTransaction(stakingTx);\n\n const psbt = staking.toUnbondingPsbt(unbondingTx, stakingTx);\n\n const contracts: Contract[] = [\n {\n id: ContractId.STAKING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n minUnbondingTime: params.unbondingTime,\n stakingDuration: stakingInput.stakingTimelock,\n },\n },\n {\n id: ContractId.UNBONDING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n unbondingTimeBlocks: params.unbondingTime,\n unbondingFeeSat: params.unbondingFeeSat,\n },\n },\n ];\n\n this.ee?.emit('delegation:unbond', {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n stakingDuration: stakingInput.stakingTimelock,\n unbondingTimeBlocks: params.unbondingTime,\n unbondingFeeSat: params.unbondingFeeSat,\n type: 'unbonding',\n });\n\n const signedUnbondingPsbtHex = await this.btcProvider.signPsbt(psbt.toHex(), {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_UNBONDING_TRANSACTION,\n },\n });\n\n const signedUnbondingTx = Psbt.fromHex(signedUnbondingPsbtHex).extractTransaction();\n\n return {\n transaction: signedUnbondingTx,\n fee,\n };\n }\n\n /**\n * Creates a signed unbonding transaction that is ready to be sent to the BTC\n * network.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param stakingInput - The staking inputs.\n * @param stakingParamsVersion - The params version that was used to create the\n * delegation in Babylon chain\n * @param stakingTx - The staking transaction.\n * @param unsignedUnbondingTx - The unsigned unbonding transaction.\n * @param covenantUnbondingSignatures - The covenant unbonding signatures.\n * It can be retrieved from the Babylon chain or API.\n * @returns The signed unbonding transaction and its fee.\n */\n async createSignedBtcUnbondingTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n stakingParamsVersion: number,\n stakingTx: Transaction,\n unsignedUnbondingTx: Transaction,\n covenantUnbondingSignatures: {\n btcPkHex: string;\n sigHex: string;\n }[]\n ): Promise<TransactionResult> {\n // Get the staking params at the time of the staking transaction\n const params = getBabylonParamByVersion(stakingParamsVersion, this.stakingParams);\n\n const { transaction: signedUnbondingTx, fee } = await this.createPartialSignedBtcUnbondingTransaction(\n stakerBtcInfo,\n stakingInput,\n stakingParamsVersion,\n stakingTx\n );\n\n // Check the computed txid of the signed unbonding transaction is the same as\n // the txid of the unsigned unbonding transaction\n if (signedUnbondingTx.getId() !== unsignedUnbondingTx.getId()) {\n throw new Error('Unbonding transaction hash does not match the computed hash');\n }\n\n // Add covenant unbonding signatures\n // Convert the params of covenants to buffer\n const covenantBuffers = params.covenantNoCoordPks.map((covenant) => Buffer.from(covenant, 'hex'));\n const witness = createCovenantWitness(\n // Since unbonding transactions always have a single input and output,\n // we expect exactly one signature in TaprootScriptSpendSig when the\n // signing is successful\n signedUnbondingTx.ins[0].witness,\n covenantBuffers,\n covenantUnbondingSignatures,\n params.covenantQuorum\n );\n // Overwrite the witness to include the covenant unbonding signatures\n signedUnbondingTx.ins[0].witness = witness;\n\n return {\n transaction: signedUnbondingTx,\n fee,\n };\n }\n\n /**\n * Creates a signed withdrawal transaction on the unbodning output expiry path\n * that is ready to be sent to the BTC network.\n * @param stakingInput - The staking inputs.\n * @param stakingParamsVersion - The params version that was used to create the\n * delegation in Babylon chain\n * @param earlyUnbondingTx - The early unbonding transaction.\n * @param feeRate - The fee rate in satoshis per byte. Typical value for the\n * fee rate is above 1. If the fee rate is too low, the transaction will not\n * be included in a block.\n * @returns The signed withdrawal transaction and its fee.\n */\n async createSignedBtcWithdrawEarlyUnbondedTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n stakingParamsVersion: number,\n earlyUnbondingTx: Transaction,\n feeRate: number\n ): Promise<TransactionResult> {\n const params = getBabylonParamByVersion(stakingParamsVersion, this.stakingParams);\n\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const { psbt: unbondingPsbt, fee } = staking.createWithdrawEarlyUnbondedTransaction(earlyUnbondingTx, feeRate);\n\n const contracts: Contract[] = [\n {\n id: ContractId.WITHDRAW,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n timelockBlocks: params.unbondingTime,\n },\n },\n ];\n\n this.ee?.emit('delegation:withdraw', {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n timelockBlocks: params.unbondingTime,\n type: 'early-unbonded',\n });\n\n const signedWithdrawalPsbtHex = await this.btcProvider.signPsbt(unbondingPsbt.toHex(), {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_WITHDRAW_TRANSACTION,\n },\n });\n\n return {\n transaction: Psbt.fromHex(signedWithdrawalPsbtHex).extractTransaction(),\n fee,\n };\n }\n\n /**\n * Creates a signed withdrawal transaction on the staking output expiry path\n * that is ready to be sent to the BTC network.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param stakingInput - The staking inputs.\n * @param stakingParamsVersion - The params version that was used to create the\n * delegation in Babylon chain\n * @param stakingTx - The staking transaction.\n * @param feeRate - The fee rate in satoshis per byte. Typical value for the\n * fee rate is above 1. If the fee rate is too low, the transaction will not\n * be included in a block.\n * @returns The signed withdrawal transaction and its fee.\n */\n async createSignedBtcWithdrawStakingExpiredTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n stakingParamsVersion: number,\n stakingTx: Transaction,\n feeRate: number\n ): Promise<TransactionResult> {\n const params = getBabylonParamByVersion(stakingParamsVersion, this.stakingParams);\n\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const { psbt, fee } = staking.createWithdrawStakingExpiredPsbt(stakingTx, feeRate);\n\n const contracts: Contract[] = [\n {\n id: ContractId.WITHDRAW,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n timelockBlocks: stakingInput.stakingTimelock,\n },\n },\n ];\n\n this.ee?.emit('delegation:withdraw', {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n timelockBlocks: stakingInput.stakingTimelock,\n type: 'staking-expired',\n });\n\n const signedWithdrawalPsbtHex = await this.btcProvider.signPsbt(psbt.toHex(), {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_WITHDRAW_TRANSACTION,\n },\n });\n\n return {\n transaction: Psbt.fromHex(signedWithdrawalPsbtHex).extractTransaction(),\n fee,\n };\n }\n\n /**\n * Creates a signed withdrawal transaction for the expired slashing output that\n * is ready to be sent to the BTC network.\n * @param stakerBtcInfo - The staker BTC info which includes the BTC address\n * and the no-coord public key in hex format.\n * @param stakingInput - The staking inputs.\n * @param stakingParamsVersion - The params version that was used to create the\n * delegation in Babylon chain\n * @param slashingTx - The slashing transaction.\n * @param feeRate - The fee rate in satoshis per byte. Typical value for the\n * fee rate is above 1. If the fee rate is too low, the transaction will not\n * be included in a block.\n * @returns The signed withdrawal transaction and its fee.\n */\n async createSignedBtcWithdrawSlashingTransaction(\n stakerBtcInfo: StakerInfo,\n stakingInput: StakingInputs,\n stakingParamsVersion: number,\n slashingTx: Transaction,\n feeRate: number\n ): Promise<TransactionResult> {\n const params = getBabylonParamByVersion(stakingParamsVersion, this.stakingParams);\n\n const staking = new Staking(\n this.network,\n stakerBtcInfo,\n params,\n stakingInput.finalityProviderPksNoCoordHex,\n stakingInput.stakingTimelock\n );\n\n const { psbt, fee } = staking.createWithdrawSlashingPsbt(slashingTx, feeRate);\n\n const contracts: Contract[] = [\n {\n id: ContractId.WITHDRAW,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n timelockBlocks: params.unbondingTime,\n },\n },\n ];\n\n this.ee?.emit('delegation:withdraw', {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n timelockBlocks: params.unbondingTime,\n type: 'slashing',\n });\n\n const signedWithrawSlashingPsbtHex = await this.btcProvider.signPsbt(psbt.toHex(), {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_WITHDRAW_TRANSACTION,\n },\n });\n\n return {\n transaction: Psbt.fromHex(signedWithrawSlashingPsbtHex).extractTransaction(),\n fee,\n };\n }\n\n /**\n * Creates a proof of possession for the staker based on ECDSA signature.\n * @param bech32Address - The staker's bech32 address.\n * @returns The proof of possession.\n */\n async createProofOfPossession(\n channel: 'delegation:create' | 'delegation:register' | 'delegation:expand',\n bech32Address: string,\n stakerBtcAddress: string\n ): Promise<ProofOfPossessionBTC> {\n let sigType: BTCSigType = BTCSigType.ECDSA;\n\n // For Taproot or Native SegWit addresses, use the BIP322 signature scheme\n // in the proof of possession as it uses the same signature type as the regular\n // input UTXO spend. For legacy addresses, use the ECDSA signature scheme.\n if (isTaproot(stakerBtcAddress, this.network) || isNativeSegwit(stakerBtcAddress, this.network)) {\n sigType = BTCSigType.BIP322;\n }\n\n const [chainId, babyTipHeight] = await Promise.all([\n this.babylonProvider.getChainId?.(),\n this.babylonProvider.getCurrentHeight?.(),\n ]);\n\n const upgradeConfig = this.upgradeConfig?.pop;\n\n // Get the message to sign for the proof of possession\n const messageToSign = buildPopMessage(\n bech32Address,\n babyTipHeight,\n chainId,\n upgradeConfig && {\n upgradeHeight: upgradeConfig.upgradeHeight,\n version: upgradeConfig.version,\n }\n );\n\n this.ee?.emit(channel, {\n messageToSign,\n type: 'proof-of-possession',\n });\n\n const signedBabylonAddress = await this.btcProvider.signMessage(\n messageToSign,\n sigType === BTCSigType.BIP322 ? 'bip322-simple' : 'ecdsa'\n );\n\n let btcSig: Uint8Array;\n if (sigType === BTCSigType.BIP322) {\n const bip322Sig = BIP322Sig.fromPartial({\n address: stakerBtcAddress,\n sig: Buffer.from(signedBabylonAddress, 'base64'),\n });\n // Encode the BIP322 protobuf message to a Uint8Array\n btcSig = BIP322Sig.encode(bip322Sig).finish();\n } else {\n // Encode the ECDSA signature to a Uint8Array\n btcSig = Buffer.from(signedBabylonAddress, 'base64');\n }\n\n return {\n btcSigType: sigType,\n btcSig,\n };\n }\n\n /**\n * Creates the unbonding, slashing, and unbonding slashing transactions and\n * PSBTs.\n * @param stakingInstance - The staking instance.\n * @param stakingTx - The staking transaction.\n * @returns The unbonding, slashing, and unbonding slashing transactions and\n * PSBTs.\n */\n private async createDelegationTransactionsAndPsbts(stakingInstance: Staking, stakingTx: Transaction) {\n const { transaction: unbondingTx } = stakingInstance.createUnbondingTransaction(stakingTx);\n\n // Create slashing transactions and extract signatures\n const { psbt: slashingPsbt } = stakingInstance.createStakingOutputSlashingPsbt(stakingTx);\n\n const { psbt: unbondingSlashingPsbt } = stakingInstance.createUnbondingOutputSlashingPsbt(unbondingTx);\n\n return {\n unbondingTx,\n slashingPsbt,\n unbondingSlashingPsbt,\n };\n }\n\n /**\n * Creates a protobuf message for the BTC delegation.\n * @param channel - The event channel to emit the message on.\n * @param stakingInstance - The staking instance.\n * @param stakingInput - The staking inputs.\n * @param stakingTx - The staking transaction.\n * @param bech32Address - The staker's babylon chain bech32 address\n * @param stakerBtcInfo - The staker's BTC information such as address and\n * public key\n * @param params - The staking parameters.\n * @param options - The options for the BTC delegation.\n * @param options.inclusionProof - The inclusion proof of the staking\n * transaction.\n * @param options.delegationExpansionInfo - The information for the BTC\n * delegation expansion.\n * @returns The protobuf message.\n */\n public async createBtcDelegationMsg(\n channel: 'delegation:create' | 'delegation:register' | 'delegation:expand',\n stakingInstance: Staking,\n stakingInput: StakingInputs,\n stakingTx: Transaction,\n bech32Address: string,\n stakerBtcInfo: StakerInfo,\n params: StakingParams,\n options?: {\n inclusionProof?: btcstaking.InclusionProof;\n delegationExpansionInfo?: {\n previousStakingTx: Transaction;\n fundingTx: Transaction;\n };\n }\n ): Promise<{\n typeUrl: string;\n value: btcstakingtx.MsgCreateBTCDelegation | btcstakingtx.MsgBtcStakeExpand;\n }> {\n if (!params.slashing) {\n throw new StakingError(\n StakingErrorCode.INVALID_PARAMS,\n 'Slashing parameters are required for creating delegation message'\n );\n }\n\n const { unbondingTx, slashingPsbt, unbondingSlashingPsbt } = await this.createDelegationTransactionsAndPsbts(\n stakingInstance,\n stakingTx\n );\n\n const slashingContracts: Contract[] = [\n {\n id: ContractId.STAKING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n minUnbondingTime: params.unbondingTime,\n stakingDuration: stakingInput.stakingTimelock,\n },\n },\n {\n id: ContractId.SLASHING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n unbondingTimeBlocks: params.unbondingTime,\n slashingFeeSat: params.slashing.minSlashingTxFeeSat,\n },\n },\n {\n id: ContractId.SLASHING_BURN,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n slashingPkScriptHex: params.slashing.slashingPkScriptHex,\n },\n },\n ];\n\n // Sign the slashing PSBT\n this.ee?.emit(channel, {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n unbondingTimeBlocks: params.unbondingTime,\n stakingDuration: stakingInput.stakingTimelock,\n slashingFeeSat: params.slashing.minSlashingTxFeeSat,\n slashingPkScriptHex: params.slashing.slashingPkScriptHex,\n type: 'staking-slashing',\n });\n\n const signedSlashingPsbtHex = await this.btcProvider.signPsbt(slashingPsbt.toHex(), {\n contracts: slashingContracts,\n action: {\n name: ActionName.SIGN_BTC_SLASHING_TRANSACTION,\n },\n });\n\n const signedSlashingTx = Psbt.fromHex(signedSlashingPsbtHex).extractTransaction();\n const slashingSig = extractFirstSchnorrSignatureFromTransaction(signedSlashingTx);\n if (!slashingSig) {\n throw new Error('No signature found in the staking output slashing PSBT');\n }\n\n const unbondingSlashingContracts: Contract[] = [\n {\n id: ContractId.UNBONDING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n unbondingTimeBlocks: params.unbondingTime,\n unbondingFeeSat: params.unbondingFeeSat,\n },\n },\n {\n id: ContractId.SLASHING,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n unbondingTimeBlocks: params.unbondingTime,\n slashingFeeSat: params.slashing.minSlashingTxFeeSat,\n },\n },\n {\n id: ContractId.SLASHING_BURN,\n params: {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n slashingPkScriptHex: params.slashing.slashingPkScriptHex,\n },\n },\n ];\n\n // Sign the unbonding slashing PSBT\n this.ee?.emit(channel, {\n stakerPk: stakerBtcInfo.publicKeyNoCoordHex,\n finalityProviders: stakingInput.finalityProviderPksNoCoordHex,\n covenantPks: params.covenantNoCoordPks,\n covenantThreshold: params.covenantQuorum,\n unbondingTimeBlocks: params.unbondingTime,\n unbondingFeeSat: params.unbondingFeeSat,\n slashingFeeSat: params.slashing.minSlashingTxFeeSat,\n slashingPkScriptHex: params.slashing.slashingPkScriptHex,\n type: 'unbonding-slashing',\n });\n\n const signedUnbondingSlashingPsbtHex = await this.btcProvider.signPsbt(unbondingSlashingPsbt.toHex(), {\n contracts: unbondingSlashingContracts,\n action: {\n name: ActionName.SIGN_BTC_UNBONDING_SLASHING_TRANSACTION,\n },\n });\n\n const signedUnbondingSlashingTx = Psbt.fromHex(signedUnbondingSlashingPsbtHex).extractTransaction();\n const unbondingSignatures = extractFirstSchnorrSignatureFromTransaction(signedUnbondingSlashingTx);\n if (!unbondingSignatures) {\n throw new Error('No signature found in the unbonding output slashing PSBT');\n }\n\n // Create proof of possession\n const proofOfPossession = await this.createProofOfPossession(channel, bech32Address, stakerBtcInfo.address);\n\n const commonMsg = {\n stakerAddr: bech32Address,\n pop: proofOfPossession,\n btcPk: Uint8Array.from(Buffer.from(stakerBtcInfo.publicKeyNoCoordHex, 'hex')),\n fpBtcPkList: stakingInput.finalityProviderPksNoCoordHex.map((pk) => Uint8Array.from(Buffer.from(pk, 'hex'))),\n stakingTime: stakingInput.stakingTimelock,\n stakingValue: stakingInput.stakingAmountSat,\n stakingTx: Uint8Array.from(stakingTx.toBuffer()),\n slashingTx: Uint8Array.from(Buffer.from(clearTxSignatures(signedSlashingTx).toHex(), 'hex')),\n delegatorSlashingSig: Uint8Array.from(slashingSig),\n unbondingTime: params.unbondingTime,\n unbondingTx: Uint8Array.from(unbondingTx.toBuffer()),\n unbondingValue: stakingInput.stakingAmountSat - params.unbondingFeeSat,\n unbondingSlashingTx: Uint8Array.from(Buffer.from(clearTxSignatures(signedUnbondingSlashingTx).toHex(), 'hex')),\n delegatorUnbondingSlashingSig: Uint8Array.from(unbondingSignatures),\n };\n\n // If the delegation is an expansion, we use the MsgBtcStakeExpand message\n if (options?.delegationExpansionInfo) {\n const fundingTx = Uint8Array.from(options.delegationExpansionInfo.fundingTx.toBuffer());\n const msg = btcstakingtx.MsgBtcStakeExpand.fromPartial({\n ...commonMsg,\n previousStakingTxHash: options.delegationExpansionInfo.previousStakingTx.getId(),\n fundingTx,\n });\n return {\n typeUrl: BABYLON_REGISTRY_TYPE_URLS.MsgBtcStakeExpand,\n value: msg,\n };\n }\n\n // Otherwise, it's a new staking delegation\n const msg: btcstakingtx.MsgCreateBTCDelegation = btcstakingtx.MsgCreateBTCDelegation.fromPartial({\n ...commonMsg,\n stakingTxInclusionProof: options?.inclusionProof,\n });\n\n return {\n typeUrl: BABYLON_REGISTRY_TYPE_URLS.MsgCreateBTCDelegation,\n value: msg,\n };\n }\n\n /**\n * Gets the inclusion proof for the staking transaction.\n * See the type `InclusionProof` for more information\n * @param inclusionProof - The inclusion proof.\n * @returns The inclusion proof.\n */\n private getInclusionProof(inclusionProof: InclusionProof): btcstaking.InclusionProof {\n const { pos, merkle, blockHashHex } = inclusionProof;\n const proofHex = deriveMerkleProof(merkle);\n\n const hash = reverseBuffer(Uint8Array.from(Buffer.from(blockHashHex, 'hex')));\n const inclusionProofKey: btccheckpoint.TransactionKey = btccheckpoint.TransactionKey.fromPartial({\n index: pos,\n hash,\n });\n return btcstaking.InclusionProof.fromPartial({\n key: inclusionProofKey,\n proof: Uint8Array.from(Buffer.from(proofHex, 'hex')),\n });\n }\n}\n\n/**\n * Get the staker signature from the unbonding transaction\n * This is used mostly for unbonding transactions from phase-1(Observable)\n * @param unbondingTx - The unbonding transaction\n * @returns The staker signature\n */\nexport const getUnbondingTxStakerSignature = (unbondingTx: Transaction): string => {\n try {\n // There is only one input and one output in the unbonding transaction\n return unbondingTx.ins[0].witness[0].toString('hex');\n } catch (error) {\n throw StakingError.fromUnknown(error, StakingErrorCode.INVALID_INPUT, 'Failed to get staker signature');\n }\n};\n", "export const BABYLON_REGISTRY_TYPE_URLS = {\n MsgCreateBTCDelegation: \"/babylon.btcstaking.v1.MsgCreateBTCDelegation\",\n MsgBtcStakeExpand: \"/babylon.btcstaking.v1.MsgBtcStakeExpand\",\n};\n", "/**\n * Reverses the order of bytes in a buffer.\n * @param buffer - The buffer to reverse.\n * @returns A new buffer with the bytes reversed.\n */\nexport const reverseBuffer = (buffer: Uint8Array): Uint8Array => {\n const clonedBuffer = new Uint8Array(buffer);\n if (clonedBuffer.length < 1) return clonedBuffer;\n for (let i = 0, j = clonedBuffer.length - 1; i < clonedBuffer.length / 2; i++, j--) {\n let tmp = clonedBuffer[i];\n clonedBuffer[i] = clonedBuffer[j];\n clonedBuffer[j] = tmp;\n }\n return clonedBuffer;\n};\n\n/**\n * Converts a Uint8Array to a hexadecimal string.\n * @param uint8Array - The Uint8Array to convert.\n * @returns The hexadecimal string.\n */\nexport const uint8ArrayToHex = (uint8Array: Uint8Array): string => {\n return Array.from(uint8Array)\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n};\n", "import { sha256 } from \"bitcoinjs-lib/src/crypto\";\n\nimport { STAKING_MODULE_ADDRESS } from \"../constants/staking\";\n\n/**\n * Creates the context string for the staker POP following RFC-036.\n * See: https://github.com/babylonlabs-io/pm/blob/main/rfc/rfc-036-replay-attack-protection.md\n * @param chainId - The Babylon chain ID\n * @param popContextVersion - The POP context version (defaults to 0)\n * @returns The hex encoded SHA-256 hash of the context string.\n */\nexport function createStakerPopContext(\n chainId: string,\n popContextVersion: number = 0,\n): string {\n // Context string format following RFC-036:\n // Format: btcstaking/{version}/{operation_type}/{chain_id}/{module_address}\n // \n // Fields:\n // - btcstaking: Protocol identifier for Bitcoin staking operations\n // - version: POP context version (integer, defaults to 0)\n // - operation_type: Type of operation (\"staker_pop\" for staker proof of possession)\n // - chain_id: The Babylon chain ID for domain separation\n // - module_address: The staking module address for additional context\n const contextString = `btcstaking/${popContextVersion}/staker_pop/${chainId}/${STAKING_MODULE_ADDRESS}`;\n return sha256(Buffer.from(contextString, \"utf8\")).toString(\"hex\");\n}\n\n/**\n * Creates the POP message to sign based on upgrade configuration and current height.\n * RFC-036: If the Babylon tip height is greater than or equal to the POP context\n * upgrade height, use the new context format, otherwise use legacy format.\n * @param currentHeight - The current Babylon tip height\n * @param bech32Address - The staker's bech32 address\n * @param chainId - The Babylon chain ID\n * @param upgradeConfig - Optional upgrade configuration with height and version\n * @returns The message to sign (either just the address or context hash + address)\n */\nexport function buildPopMessage(\n bech32Address: string,\n currentHeight?: number,\n chainId?: string,\n upgradeConfig?: { upgradeHeight: number; version: number },\n): string {\n // RFC-036: If upgrade is configured and current height >= upgrade height, use new context format\n // https://github.com/babylonlabs-io/pm/blob/main/rfc/rfc-036-replay-attack-protection.md\n if (\n chainId !== undefined &&\n upgradeConfig?.upgradeHeight !== undefined &&\n upgradeConfig.version !== undefined &&\n currentHeight !== undefined &&\n currentHeight >= upgradeConfig.upgradeHeight\n ) {\n const contextHash = createStakerPopContext(chainId, upgradeConfig.version);\n return contextHash + bech32Address;\n }\n\n return bech32Address;\n}", "/**\n * Staking module address for the Babylon Genesis chain.\n * This address is derived deterministically from the module name and is the same across all environments.\n */\nexport const STAKING_MODULE_ADDRESS = \"bbn13837feaxn8t0zvwcjwhw7lhpgdcx4s36eqteah\"; ", "import { StakingParams, VersionedStakingParams } from \"../../types/params\";\n\n/*\n Get the Babylon params version by BTC height\n @param height - The BTC height\n @param babylonParamsVersions - The Babylon params versions\n @returns The Babylon params\n*/\nexport const getBabylonParamByBtcHeight = (\n height: number,\n babylonParamsVersions: VersionedStakingParams[],\n): StakingParams => {\n // Sort by btcActivationHeight in ascending order\n const sortedParams = [...babylonParamsVersions].sort(\n (a, b) => b.btcActivationHeight - a.btcActivationHeight,\n );\n\n // Find first params where height is >= btcActivationHeight\n const params = sortedParams.find(\n (p) => height >= p.btcActivationHeight,\n );\n if (!params) throw new Error(`Babylon params not found for height ${height}`);\n return params;\n};\n\n/*\n Get the Babylon params by version\n @param version - The Babylon params version\n @param babylonParams - The Babylon params\n @returns The Babylon params\n*/\nexport const getBabylonParamByVersion = (\n version: number,\n babylonParams: VersionedStakingParams[],\n): StakingParams => {\n const params = babylonParams.find((p) => p.version === version);\n if (!params) throw new Error(`Babylon params not found for version ${version}`);\n return params;\n};", "import { opcodes, script } from \"bitcoinjs-lib\";\nimport {\n MAGIC_BYTES_LEN,\n StakingScriptData,\n StakingScripts\n} from \"../stakingScript\";\n\n// Extending StakingScripts to add an extra field\nexport interface ObservableStakingScripts extends StakingScripts {\n dataEmbedScript: Buffer;\n}\n\nexport class ObservableStakingScriptData extends StakingScriptData {\n // The magic bytes used to identify the staking transaction on Babylon\n // through the data return script\n magicBytes: Buffer;\n constructor(\n stakerKey: Buffer,\n finalityProviderKeys: Buffer[],\n covenantKeys: Buffer[],\n covenantThreshold: number,\n stakingTimelock: number,\n unbondingTimelock: number,\n magicBytes: Buffer,\n ) {\n super(\n stakerKey,\n finalityProviderKeys,\n covenantKeys,\n covenantThreshold,\n stakingTimelock,\n unbondingTimelock,\n );\n if (\n !magicBytes\n ) {\n throw new Error(\"Missing required input values\");\n }\n // check that the magic bytes are 4 in length\n if (magicBytes.length != MAGIC_BYTES_LEN) {\n throw new Error(\"Invalid script data provided\");\n }\n\n this.magicBytes = magicBytes;\n }\n\n /**\n * Builds a data embed script for staking in the form:\n * OP_RETURN || <serializedStakingData>\n * where serializedStakingData is the concatenation of:\n * MagicBytes || Version || StakerPublicKey || FinalityProviderPublicKey || StakingTimeLock\n * Note: Only a single finality provider key is supported for now in phase 1\n * @throws {Error} If the number of finality provider keys is not equal to 1.\n * @returns {Buffer} The compiled data embed script.\n */\n buildDataEmbedScript(): Buffer {\n // Only accept a single finality provider key for now\n if (this.finalityProviderKeys.length != 1) {\n throw new Error(\"Only a single finality provider key is supported\");\n }\n // 1 byte for version\n const version = Buffer.alloc(1);\n version.writeUInt8(0);\n // 2 bytes for staking time\n const stakingTimeLock = Buffer.alloc(2);\n // big endian\n stakingTimeLock.writeUInt16BE(this.stakingTimeLock);\n const serializedStakingData = Buffer.concat([\n this.magicBytes,\n version,\n this.stakerKey,\n this.finalityProviderKeys[0],\n stakingTimeLock,\n ]);\n return script.compile([opcodes.OP_RETURN, serializedStakingData]);\n }\n\n /**\n * Builds the staking scripts.\n * @returns {ObservableStakingScripts} The staking scripts that can be used to stake.\n * contains the timelockScript, unbondingScript, slashingScript,\n * unbondingTimelockScript, and dataEmbedScript.\n * @throws {Error} If script data is invalid.\n */\n buildScripts(): ObservableStakingScripts {\n const scripts = super.buildScripts();\n return {\n ...scripts,\n dataEmbedScript: this.buildDataEmbedScript(),\n };\n }\n}\n", "import { ObservableVersionedStakingParams } from \"../../types/params\";\nimport { UTXO } from \"../../types/UTXO\";\nimport { StakingError, StakingErrorCode } from \"../../error\";\nimport { stakingTransaction } from \"../transactions\";\nimport { isTaproot } from \"../../utils/btc\";\nimport { toBuffers } from \"../../utils/staking\";\nimport { validateStakingTxInputData } from \"../../utils/staking/validation\";\nimport { TransactionResult } from \"../../types/transaction\";\nimport { ObservableStakingScriptData, ObservableStakingScripts } from \"./observableStakingScript\";\nimport { StakerInfo, Staking } from \"..\";\nimport { networks, Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { stakingPsbt } from \"../psbt\";\nexport * from \"./observableStakingScript\";\n\n/**\n * ObservableStaking is a class that provides an interface to create observable\n * staking transactions for the Babylon Staking protocol.\n * \n * The class requires a network and staker information to create staking\n * transactions.\n * The staker information includes the staker's address and \n * public key(without coordinates).\n */\nexport class ObservableStaking extends Staking {\n params: ObservableVersionedStakingParams;\n constructor(\n network: networks.Network,\n stakerInfo: StakerInfo,\n params: ObservableVersionedStakingParams,\n finalityProviderPksNoCoordHex: string[],\n stakingTimelock: number,\n ) {\n super(\n network,\n stakerInfo,\n params,\n finalityProviderPksNoCoordHex,\n stakingTimelock,\n );\n if (!params.tag) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT, \n \"Observable staking parameters must include tag\",\n );\n }\n if (!params.btcActivationHeight) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Observable staking parameters must include a positive activation height\",\n );\n }\n // Observable is legacy phase-1 staking which require exactly \n // one finality provider public key\n if (finalityProviderPksNoCoordHex.length !== 1) {\n throw new StakingError(\n StakingErrorCode.INVALID_INPUT,\n \"Observable staking requires exactly one finality provider public key\",\n );\n }\n // Override the staking parameters type to ObservableStakingParams\n this.params = params;\n }\n \n /**\n * Build the staking scripts for observable staking.\n * This method overwrites the base method to include the OP_RETURN tag based \n * on the tag provided in the parameters.\n * \n * @returns {ObservableStakingScripts} - The staking scripts for observable staking.\n * @throws {StakingError} - If the scripts cannot be built.\n */\n buildScripts(): ObservableStakingScripts {\n const { covenantQuorum, covenantNoCoordPks, unbondingTime, tag } = this.params;\n // Create staking script data\n let stakingScriptData;\n try {\n stakingScriptData = new ObservableStakingScriptData(\n Buffer.from(this.stakerInfo.publicKeyNoCoordHex, \"hex\"),\n this.finalityProviderPksNoCoordHex.map((pk) => Buffer.from(pk, \"hex\")),\n toBuffers(covenantNoCoordPks),\n covenantQuorum,\n this.stakingTimelock,\n unbondingTime,\n Buffer.from(tag, \"hex\"),\n );\n } catch (error: unknown) {\n throw StakingError.fromUnknown(\n error, StakingErrorCode.SCRIPT_FAILURE, \n \"Cannot build staking script data\",\n );\n }\n\n // Build scripts\n let scripts;\n try {\n scripts = stakingScriptData.buildScripts();\n } catch (error: unknown) {\n throw StakingError.fromUnknown(\n error, StakingErrorCode.SCRIPT_FAILURE,\n \"Cannot build staking scripts\",\n );\n }\n return scripts;\n }\n\n /**\n * Create a staking transaction for observable staking.\n * This overwrites the method from the Staking class with the addtion\n * of the \n * 1. OP_RETURN tag in the staking scripts\n * 2. lockHeight parameter\n * \n * @param {number} stakingAmountSat - The amount to stake in satoshis.\n * @param {UTXO[]} inputUTXOs - The UTXOs to use as inputs for the staking \n * transaction.\n * @param {number} feeRate - The fee rate for the transaction in satoshis per byte.\n * @returns {TransactionResult} - An object containing the unsigned transaction,\n * and fee\n */\n public createStakingTransaction(\n stakingAmountSat: number,\n inputUTXOs: UTXO[],\n feeRate: number,\n ): TransactionResult {\n validateStakingTxInputData(\n stakingAmountSat,\n this.stakingTimelock,\n this.params,\n inputUTXOs,\n feeRate,\n );\n\n const scripts = this.buildScripts();\n\n // Create the staking transaction\n try {\n const { transaction, fee } = stakingTransaction(\n scripts,\n stakingAmountSat,\n this.stakerInfo.address,\n inputUTXOs,\n this.network,\n feeRate,\n // `lockHeight` is exclusive of the provided value.\n // For example, if a Bitcoin height of X is provided,\n // the transaction will be included starting from height X+1.\n // https://learnmeabitcoin.com/technical/transaction/locktime/\n this.params.btcActivationHeight - 1,\n );\n \n return {\n transaction,\n fee,\n };\n } catch (error: unknown) {\n throw StakingError.fromUnknown(\n error, StakingErrorCode.BUILD_TRANSACTION_FAILURE,\n \"Cannot build unsigned staking transaction\",\n );\n }\n }\n\n /**\n * Create a staking psbt for observable staking.\n * \n * @param {Transaction} stakingTx - The staking transaction.\n * @param {UTXO[]} inputUTXOs - The UTXOs to use as inputs for the staking \n * transaction.\n * @returns {Psbt} - The psbt.\n */\n public toStakingPsbt(\n stakingTx: Transaction,\n inputUTXOs: UTXO[],\n ): Psbt {\n return stakingPsbt(\n stakingTx,\n this.network,\n inputUTXOs,\n isTaproot(\n this.stakerInfo.address, this.network\n ) ? Buffer.from(this.stakerInfo.publicKeyNoCoordHex, \"hex\") : undefined,\n );\n }\n}\n", "/**\n * Base interface for staking parameters that define the rules and constraints\n * for staking operations.\n */\nexport interface StakingParams {\n covenantNoCoordPks: string[];\n covenantQuorum: number;\n unbondingTime: number;\n unbondingFeeSat: number;\n maxStakingAmountSat: number;\n minStakingAmountSat: number;\n maxStakingTimeBlocks: number;\n minStakingTimeBlocks: number;\n slashing?: {\n slashingPkScriptHex: string;\n slashingRate: number;\n minSlashingTxFeeSat: number;\n }\n}\n\n/**\n * Type for StakingParams where slashing is required\n */\nexport type StakingParamsWithSlashing = StakingParams & {\n slashing: NonNullable<StakingParams['slashing']>;\n};\n\n/**\n * Type guard to check if slashing exists in StakingParams\n */\nexport function hasSlashing(params: StakingParams): params is StakingParams & { slashing: NonNullable<StakingParams['slashing']> } {\n return params.slashing !== undefined;\n}\n\n/**\n * Extension of StakingParams that includes activation height and version information.\n * These parameters are used to identify and select the appropriate staking rules at\n * different blockchain heights, but do not affect the actual staking transaction content.\n */\nexport interface VersionedStakingParams extends StakingParams {\n btcActivationHeight: number;\n version: number;\n}\n\n/**\n * Extension of VersionedStakingParams that includes a tag field for observability.\n */\nexport interface ObservableVersionedStakingParams extends VersionedStakingParams {\n tag: string;\n}"],
5
+ "mappings": ";AASO,IAAM,eAAN,MAAM,sBAAqB,MAAM;AAAA,EAEtC,YAAY,MAAwB,SAAkB;AACpD,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,OAAO,YACL,OAAgB,MAAwB,aAC1B;AACd,QAAI,iBAAiB,eAAc;AACjC,aAAO;AAAA,IACT;AAEA,QAAI,iBAAiB,OAAO;AAC1B,aAAO,IAAI,cAAa,MAAM,MAAM,OAAO;AAAA,IAC7C;AACA,WAAO,IAAI,cAAa,MAAM,WAAW;AAAA,EAC3C;AACF;;;AC7BA,YAAY,SAAS;AACrB,SAAS,SAAS,YAAY,gBAAgB;;;ACAvC,IAAM,0BAA0B;;;ADIhC,IAAM,eAAe,MAAM;AAChC,aAAW,GAAG;AAChB;AASO,IAAM,wBAAwB,CACnC,YACA,YACY;AACZ,MAAI;AACF,WAAO,CAAC,CAAC,QAAQ,eAAe,YAAY,OAAO;AAAA,EACrD,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AASO,IAAM,YAAY,CACvB,gBACA,YACY;AACZ,MAAI;AACF,UAAM,UAAU,QAAQ,WAAW,cAAc;AACjD,QAAI,QAAQ,YAAY,GAAG;AACzB,aAAO;AAAA,IACT;AAKA,QAAI,QAAQ,WAAW,SAAS,QAAQ,QAAQ;AAE9C,aAAO,eAAe,WAAW,MAAM;AAAA,IACzC,WAAW,QAAQ,WAAW,SAAS,QAAQ,QAAQ;AAErD,aACE,eAAe,WAAW,MAAM,KAAK,eAAe,WAAW,MAAM;AAAA,IAEzE;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AASO,IAAM,iBAAiB,CAC5B,eACA,YACY;AACZ,MAAI;AACF,UAAM,UAAU,QAAQ,WAAW,aAAa;AAChD,QAAI,QAAQ,YAAY,GAAG;AACzB,aAAO;AAAA,IACT;AAKA,QAAI,QAAQ,WAAW,SAAS,QAAQ,QAAQ;AAE9C,aAAO,cAAc,WAAW,MAAM;AAAA,IACxC,WAAW,QAAQ,WAAW,SAAS,QAAQ,QAAQ;AAErD,aAAO,cAAc,WAAW,MAAM;AAAA,IACxC;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAQO,IAAM,0BAA0B,CAAC,kBAAmC;AACzE,MAAI;AACF,UAAM,YAAY,OAAO,KAAK,eAAe,KAAK;AAClD,WAAO,+BAA+B,SAAS;AAAA,EACjD,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AASO,IAAM,sBAAsB,CAAC,UAA0B;AAC5D,QAAM,YAAY,OAAO,KAAK,OAAO,KAAK;AAE1C,QAAM,yBACJ,UAAU,WAAW,0BACjB,YACA,UAAU,SAAS,GAAG,EAAE;AAG9B,MAAI,CAAC,+BAA+B,sBAAsB,GAAG;AAC3D,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AAEA,SAAO,uBAAuB,SAAS,KAAK;AAC9C;AAEA,IAAM,iCAAiC,CAAC,aAA8B;AACpE,MAAI,SAAS,WAAW,yBAAyB;AAC/C,WAAO;AAAA,EACT;AAGA,QAAM,oBAAoB,OAAO,OAAO,CAAC,OAAO,KAAK,CAAC,CAAI,CAAC,GAAG,QAAQ,CAAC;AACvE,QAAM,mBAAmB,OAAO,OAAO,CAAC,OAAO,KAAK,CAAC,CAAI,CAAC,GAAG,QAAQ,CAAC;AAEtE,SAAW,YAAQ,iBAAiB,KAAS,YAAQ,gBAAgB;AACvE;AAQO,IAAM,sBAAsB,CAAC,SAAyB;AAC3D,MAAI,SAAS,IAAI;AACf,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AACA,SAAO,OAAO,KAAK,MAAM,KAAK,EAAE,QAAQ;AAC1C;;;AE5JA,SAAS,WAAAA,UAAmB,gBAA6B;;;ACCzD,IAAM,MACJ;AACK,IAAM,iBAAiB,OAAO,KAAK,KAAK,KAAK,EAAE,SAAS,GAAG,EAAE;;;ADiB7D,IAAM,iCAAiC,CAC5C,SAMA,SACA,WACwB;AACxB,QAAM,oBAAoB,wBAAwB,SAAS,OAAO;AAClE,QAAM,qBAAgE;AAAA,IACpE;AAAA,MACE,cAAc,kBAAkB;AAAA,MAChC,OAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,QAAQ,iBAAiB;AAE3B,uBAAmB,KAAK;AAAA,MACtB,cAAc,QAAQ;AAAA,MACtB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAUO,IAAM,0BAA0B,CACrC,SAKA,YACG;AAEH,QAAM,aAAsB;AAAA,IAC1B;AAAA,MACE,QAAQ,QAAQ;AAAA,IAClB;AAAA,IACA,CAAC,EAAE,QAAQ,QAAQ,gBAAgB,GAAG,EAAE,QAAQ,QAAQ,eAAe,CAAC;AAAA,EAC1E;AAGA,QAAM,gBAAgB,SAAS,KAAK;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,CAAC,cAAc,SAAS;AAC1B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe,cAAc;AAAA,IAC7B,cAAcC,SAAQ,eAAe,cAAc,SAAS,OAAO;AAAA,EACrE;AACF;AAUO,IAAM,4BAA4B,CACvC,SAIA,YACG;AACH,QAAM,mBAA4B;AAAA,IAChC;AAAA,MACE,QAAQ,QAAQ;AAAA,IAClB;AAAA,IACA,EAAE,QAAQ,QAAQ,wBAAwB;AAAA,EAC5C;AAEA,QAAM,kBAAkB,SAAS,KAAK;AAAA,IACpC;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,EACF,CAAC;AAED,MAAI,CAAC,gBAAgB,SAAS;AAC5B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe,gBAAgB;AAAA,IAC/B,cAAcA,SAAQ,eAAe,gBAAgB,SAAS,OAAO;AAAA,EACvE;AACF;AAYO,IAAM,uBAAuB,CAClC,SAGA,YACG;AACH,QAAM,iBAAiB,SAAS,KAAK;AAAA,IACnC;AAAA,IACA,YAAY,EAAE,QAAQ,QAAQ,wBAAwB;AAAA,IACtD;AAAA,EACF,CAAC;AACD,QAAM,wBAAwB,eAAe;AAE7C,MAAI,CAAC,uBAAuB;AAC1B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,cAAcA,SAAQ,eAAe,uBAAuB,OAAO;AAAA,EACrE;AACF;AAWO,IAAM,4BAA4B,CACvC,IACA,eACA,YACG;AACH,QAAM,QAAQ,GAAG,KAAK,UAAU,CAAC,WAAW;AAC1C,QAAI;AACF,aAAOA,SAAQ,iBAAiB,OAAO,QAAQ,OAAO,MAAM;AAAA,IAC9D,SAAS,OAAO;AACd,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI;AAAA;AAAA,MAER,0CAA0C,aAAa;AAAA,IACzD;AAAA,EACF;AAEA,SAAO;AACT;AASO,IAAM,YAAY,CAAC,WAA+B;AACvD,MAAI;AACF,WAAO,OAAO,IAAI,CAAC,MAAM,OAAO,KAAK,GAAG,KAAK,CAAC;AAAA,EAChD,SAAS,OAAO;AACd,UAAM,aAAa;AAAA,MACjB;AAAA;AAAA,MAEA;AAAA,IACF;AAAA,EACF;AACF;AAWO,IAAM,oBAAoB,CAAC,OAAiC;AACjE,KAAG,IAAI,QAAQ,CAAC,UAAU;AACxB,UAAM,SAAS,OAAO,MAAM,CAAC;AAC7B,UAAM,UAAU,CAAC;AAAA,EACnB,CAAC;AACD,SAAO;AACT;AAQO,IAAM,oBAAoB,CAAC,WAAqB;AACrD,QAAM,WAAW,OAAO,OAAO,CAAC,KAAa,MAAc;AACzD,WAAO,MAAM,OAAO,KAAK,GAAG,KAAK,EAAE,QAAQ,EAAE,SAAS,KAAK;AAAA,EAC7D,GAAG,EAAE;AACL,SAAO;AACT;AAaO,IAAM,8CAA8C,CACzD,sBACuB;AAEvB,aAAW,SAAS,kBAAkB,KAAK;AACzC,QAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,YAAM,mBAAmB,MAAM,QAAQ,CAAC;AAGxC,UAAI,iBAAiB,WAAW,IAAI;AAClC,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AEnRA,SAAS,MAA6B,YAAAC,iBAAgB;;;ACA/C,IAAM,iBAAiB;;;ACKvB,IAAM,gBAAgB,CAAC,YAAoB,UAAuB;AACvE,QAAM,YAAY,WAAW;AAAA,IAC3B,CAAC,MACC,oBAAoB,EAAE,IAAI,EAAE,SAAS,KAAK,MACxC,MAAM,KAAK,SAAS,KAAK,KAAK,EAAE,SAAS,MAAM;AAAA,EACrD;AACA,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR,kCAAkC,OAAO,KAAK,MAAM,IAAI,EAAE,QAAQ,EAAE,SAAS,KAAK,CAAC,cACpE,MAAM,KAAK;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;;;AClBA,SAAS,YAAAC,iBAAgB;AAKlB,IAAK,oBAAL,kBAAKC,uBAAL;AAEL,EAAAA,mBAAA,WAAQ;AAER,EAAAA,mBAAA,UAAO;AAEP,EAAAA,mBAAA,YAAS;AAET,EAAAA,mBAAA,WAAQ;AAER,EAAAA,mBAAA,UAAO;AAVG,SAAAA;AAAA,GAAA;AAwBL,IAAM,gBAAgB,CAACC,YAAsC;AAClE,MAAI;AACF,IAAAF,UAAS,MAAM,EAAE,QAAQE,QAAO,CAAC;AACjC,WAAO;AAAA,EACT,QAAQ;AAAA,EAAC;AACT,MAAI;AACF,IAAAF,UAAS,KAAK,EAAE,QAAQE,QAAO,CAAC;AAChC,WAAO;AAAA,EACT,QAAQ;AAAA,EAAC;AACT,MAAI;AACF,IAAAF,UAAS,OAAO,EAAE,QAAQE,QAAO,CAAC;AAClC,WAAO;AAAA,EACT,QAAQ;AAAA,EAAC;AACT,MAAI;AACF,IAAAF,UAAS,MAAM,EAAE,QAAQE,QAAO,CAAC;AACjC,WAAO;AAAA,EACT,QAAQ;AAAA,EAAC;AACT,MAAI;AACF,IAAAF,UAAS,KAAK,EAAE,QAAQE,QAAO,CAAC;AAChC,WAAO;AAAA,EACT,QAAQ;AAAA,EAAC;AAET,QAAM,IAAI,MAAM,qBAAqB;AACvC;;;ACpCO,IAAM,qBAAqB,CAChC,MACA,qBACsB;AACtB,QAAM,eAAe,OAAO,KAAK,KAAK,cAAc,KAAK;AACzD,QAAM,OAAO,cAAc,YAAY;AAEvC,UAAQ,MAAM;AAAA,IACZ,+BAA8B;AAC5B,UAAI,CAAC,KAAK,UAAU;AAClB,cAAM,IAAI,MAAM,yCAAyC;AAAA,MAC3D;AACA,aAAO,EAAE,gBAAgB,OAAO,KAAK,KAAK,UAAU,KAAK,EAAE;AAAA,IAC7D;AAAA,IACA,8BAA6B;AAC3B,UAAI,CAAC,KAAK,UAAU;AAClB,cAAM,IAAI,MAAM,iCAAiC;AAAA,MACnD;AACA,UAAI,CAAC,KAAK,cAAc;AACtB,cAAM,IAAI,MAAM,qCAAqC;AAAA,MACvD;AACA,aAAO;AAAA,QACL,gBAAgB,OAAO,KAAK,KAAK,UAAU,KAAK;AAAA,QAChD,cAAc,OAAO,KAAK,KAAK,cAAc,KAAK;AAAA,MACpD;AAAA,IACF;AAAA,IACA,uCAA+B;AAC7B,aAAO;AAAA,QACL,aAAa;AAAA,UACX,QAAQ;AAAA,UACR,OAAO,KAAK;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,IACA,sCAA8B;AAC5B,UAAI,CAAC,KAAK,eAAe;AACvB,cAAM,IAAI,MAAM,uCAAuC;AAAA,MACzD;AACA,aAAO;AAAA,QACL,aAAa;AAAA,UACX,QAAQ;AAAA,UACR,OAAO,KAAK;AAAA,QACd;AAAA,QACA,eAAe,OAAO,KAAK,KAAK,eAAe,KAAK;AAAA,MACtD;AAAA,IACF;AAAA,IACA,2BAA6B;AAC3B,aAAO;AAAA,QACL,aAAa;AAAA,UACX,QAAQ;AAAA,UACR,OAAO,KAAK;AAAA,QACd;AAAA;AAAA,QAEA,GAAI,oBAAoB,EAAE,gBAAgB,iBAAiB;AAAA,MAC7D;AAAA,IACF;AAAA,IACA;AACE,YAAM,IAAI,MAAM,4BAA4B,IAAI,EAAE;AAAA,EACtD;AACF;;;AJpDO,IAAM,cAAc,CACzB,WACA,SACA,YACA,qBACS;AACT,MAAI,oBAAoB,iBAAiB,WAAW,yBAAyB;AAC3E,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AAEA,QAAM,OAAO,IAAI,KAAK,EAAE,QAAQ,CAAC;AAEjC,MAAI,UAAU,YAAY,OAAW,MAAK,WAAW,UAAU,OAAO;AACtE,MAAI,UAAU,aAAa,OAAW,MAAK,YAAY,UAAU,QAAQ;AAEzE,YAAU,IAAI,QAAQ,CAAC,UAAU;AAC/B,UAAM,YAAY,cAAc,YAAY,KAAK;AACjD,UAAM,gBAAgB,mBAAmB,WAAW,gBAAgB;AAEpE,SAAK,SAAS;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,GAAG;AAAA,IACL,CAAC;AAAA,EACH,CAAC;AAED,YAAU,KAAK,QAAQ,CAAC,MAAM;AAC5B,SAAK,UAAU,EAAE,QAAQ,EAAE,QAAQ,OAAO,EAAE,MAAM,CAAC;AAAA,EACrD,CAAC;AAED,SAAO;AACT;AAeO,IAAM,uBAAuB,CAClC,SACA,WACA,uBAIA,YACA,iBACA,qBACS;AAET,QAAM,OAAO,IAAI,KAAK,EAAE,QAAQ,CAAC;AAGjC,MAAI,UAAU,YAAY,OAAW,MAAK,WAAW,UAAU,OAAO;AACtE,MAAI,UAAU,aAAa,OAAW,MAAK,YAAY,UAAU,QAAQ;AAGzE,MACE,oBAAoB,iBAAiB,WAAW,yBAChD;AACA,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AAGA,QAAM,wBAAwB,sBAAsB,UAAU,KAC5D,sBAAsB,WACxB;AACA,MAAI,CAAC,uBAAuB;AAC1B,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAAC;AAGD,MACE,cAAc,sBAAsB,MAAM,4BAC1C;AACA,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAKA,MAAI,UAAU,IAAI,WAAW,GAAG;AAC9B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,UAAU;AAI3B,MACE,OAAO,KAAK,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,KAAK,MAAM,sBAAsB,UAAU,MAAM,GAClG;AACA,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D,WAES,SAAS,CAAC,EAAE,UAAU,sBAAsB,aAAa;AAChE,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AAGA,QAAM,kBAA2B;AAAA,IAC/B,EAAE,QAAQ,gBAAgB,eAAe;AAAA,IACzC,CAAC,EAAE,QAAQ,gBAAgB,gBAAgB,GAAG,EAAE,QAAQ,gBAAgB,eAAe,CAAC;AAAA,EAC1F;AACA,QAAM,cAAc;AAAA,IAClB,QAAQ,gBAAgB;AAAA,IACxB,eAAe;AAAA,EACjB;AACA,QAAM,OAAOC,UAAS,KAAK;AAAA,IACzB;AAAA,IACA,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,MAAI,CAAC,KAAK,WAAW,KAAK,QAAQ,WAAW,GAAG;AAC9C,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,qBAAqB;AAAA,IACzB,aAAa,YAAY;AAAA,IACzB,QAAQ,YAAY;AAAA,IACpB,cAAc,KAAK,QAAQ,KAAK,QAAQ,SAAS,CAAC;AAAA,EACpD;AAIA,OAAK,SAAS;AAAA,IACZ,MAAM,SAAS,CAAC,EAAE;AAAA,IAClB,OAAO,SAAS,CAAC,EAAE;AAAA,IACnB,UAAU,SAAS,CAAC,EAAE;AAAA,IACtB,aAAa;AAAA,MACX,QAAQ,sBAAsB;AAAA,MAC9B,OAAO,sBAAsB;AAAA,IAC/B;AAAA,IACA,gBAAgB;AAAA,IAChB,eAAe,CAAC,kBAAkB;AAAA,EACpC,CAAC;AAID,QAAM,YAAY,cAAc,YAAY,SAAS,CAAC,CAAC;AACvD,QAAM,gBAAgB,mBAAmB,WAAW,gBAAgB;AAEpE,OAAK,SAAS;AAAA,IACZ,MAAM,SAAS,CAAC,EAAE;AAAA,IAClB,OAAO,SAAS,CAAC,EAAE;AAAA,IACnB,UAAU,SAAS,CAAC,EAAE;AAAA,IACtB,GAAG;AAAA,EACL,CAAC;AAGD,YAAU,KAAK,QAAQ,CAAC,MAAM;AAC5B,SAAK,UAAU,EAAE,QAAQ,EAAE,QAAQ,OAAO,EAAE,MAAM,CAAC;AAAA,EACrD,CAAC;AAED,SAAO;AACT;AAEO,IAAM,gBAAgB,CAC3B,SAMA,aACA,WACA,YACS;AACT,MAAI,YAAY,KAAK,WAAW,GAAG;AACjC,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,MAAI,YAAY,IAAI,WAAW,GAAG;AAChC,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AAEA,0BAAwB,SAAS,aAAa,OAAO;AAErD,QAAM,OAAO,IAAI,KAAK,EAAE,QAAQ,CAAC;AAEjC,MAAI,YAAY,YAAY,QAAW;AACrC,SAAK,WAAW,YAAY,OAAO;AAAA,EACrC;AACA,MAAI,YAAY,aAAa,QAAW;AACtC,SAAK,YAAY,YAAY,QAAQ;AAAA,EACvC;AAEA,QAAM,QAAQ,YAAY,IAAI,CAAC;AAC/B,QAAM,cAAc,MAAM;AAG1B,QAAM,kBAA2B;AAAA,IAC/B,EAAE,QAAQ,QAAQ,eAAe;AAAA,IACjC,CAAC,EAAE,QAAQ,QAAQ,gBAAgB,GAAG,EAAE,QAAQ,QAAQ,eAAe,CAAC;AAAA,EAC1E;AAGA,QAAM,cAAc;AAAA,IAClB,QAAQ,QAAQ;AAAA,IAChB,eAAe;AAAA,EACjB;AAGA,QAAM,OAAOA,UAAS,KAAK;AAAA,IACzB;AAAA,IACA,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,QAAM,qBAAqB;AAAA,IACzB,aAAa,YAAY;AAAA,IACzB,QAAQ,YAAY;AAAA,IACpB,cAAc,KAAK,QAAS,KAAK,QAAS,SAAS,CAAC;AAAA,EACtD;AAEA,OAAK,SAAS;AAAA,IACZ,MAAM,MAAM;AAAA,IACZ,OAAO,MAAM;AAAA,IACb,UAAU,MAAM;AAAA,IAChB,gBAAgB;AAAA,IAChB,aAAa;AAAA,MACX,OAAO,UAAU,KAAK,WAAW,EAAE;AAAA,MACnC,QAAQ,UAAU,KAAK,WAAW,EAAE;AAAA,IACtC;AAAA,IACA,eAAe,CAAC,kBAAkB;AAAA,EACpC,CAAC;AAED,OAAK,UAAU;AAAA,IACb,QAAQ,YAAY,KAAK,CAAC,EAAE;AAAA,IAC5B,OAAO,YAAY,KAAK,CAAC,EAAE;AAAA,EAC7B,CAAC;AAED,SAAO;AACT;AASA,IAAM,0BAA0B,CAC9B,SAIA,aACA,YACG;AACH,QAAM,sBAAsB,0BAA0B,SAAS,OAAO;AACtE,MACE,oBAAoB,aAAa,SAAS,KAAK,MAC/C,YAAY,KAAK,CAAC,EAAE,OAAO,SAAS,KAAK,GACzC;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACF;;;AK3SA,SAAS,SAAS,cAAc;AAGzB,IAAM,kBAAkB;AAYxB,IAAM,oBAAN,MAAwB;AAAA,EAQ7B,YAEE,WAIA,sBAIA,cAIA,mBAEA,iBAIA,mBACA;AACA,QACE,CAAC,aACD,CAAC,wBACD,CAAC,gBACD,CAAC,qBACD,CAAC,mBACD,CAAC,mBACD;AACA,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,SAAK,YAAY;AACjB,SAAK,uBAAuB;AAC5B,SAAK,eAAe;AACpB,SAAK,oBAAoB;AACzB,SAAK,kBAAkB;AACvB,SAAK,oBAAoB;AAGzB,QAAI,CAAC,KAAK,SAAS,GAAG;AACpB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAoB;AAElB,QAAI,KAAK,UAAU,UAAU,yBAAyB;AACpD,aAAO;AAAA,IACT;AAEA,QACE,KAAK,qBAAqB;AAAA,MACxB,CAAC,wBAAwB,oBAAoB,UAAU;AAAA,IACzD,GACA;AACA,aAAO;AAAA,IACT;AAEA,QACE,KAAK,aAAa,KAAK,CAAC,gBAAgB,YAAY,UAAU,uBAAuB,GACrF;AACA,aAAO;AAAA,IACT;AAGA,UAAM,SAAS;AAAA,MACb,KAAK;AAAA,MACL,GAAG,KAAK;AAAA,MACR,GAAG,KAAK;AAAA,IACV;AACA,UAAM,YAAY,IAAI,IAAI,MAAM;AAChC,QAAI,OAAO,WAAW,UAAU,MAAM;AACpC,aAAO;AAAA,IACT;AAIA,QACE,KAAK,qBAAqB,KAC1B,KAAK,oBAAoB,KAAK,aAAa,QAC3C;AACA,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,mBAAmB,KAAK,KAAK,kBAAkB,OAAO;AAC7D,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,qBAAqB,KAAK,KAAK,oBAAoB,OAAO;AACjE,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,oBAAoB,UAA0B;AAC5C,WAAO,OAAO,QAAQ;AAAA,MACpB,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,OAAO,OAAO,QAAQ;AAAA,MAC7B,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,6BAAqC;AACnC,WAAO,KAAK,oBAAoB,KAAK,eAAe;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,+BAAuC;AACrC,WAAO,KAAK,oBAAoB,KAAK,iBAAiB;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,uBAA+B;AAC7B,WAAO,OAAO,OAAO;AAAA,MACnB,KAAK,qBAAqB,KAAK,WAAW,IAAI;AAAA,MAC9C,KAAK;AAAA,QACH,KAAK;AAAA,QACL,KAAK;AAAA,QACL;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,sBAA8B;AAC5B,WAAO,OAAO,OAAO;AAAA,MACnB,KAAK,qBAAqB,KAAK,WAAW,IAAI;AAAA,MAC9C,KAAK;AAAA,QACH,KAAK;AAAA;AAAA;AAAA;AAAA,QAIL;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,MACA,KAAK;AAAA,QACH,KAAK;AAAA,QACL,KAAK;AAAA;AAAA,QAEL;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,eAA+B;AAC7B,WAAO;AAAA,MACL,gBAAgB,KAAK,2BAA2B;AAAA,MAChD,iBAAiB,KAAK,qBAAqB;AAAA,MAC3C,gBAAgB,KAAK,oBAAoB;AAAA,MACzC,yBAAyB,KAAK,6BAA6B;AAAA,IAC7D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,qBAAqB,IAAY,YAA6B;AAE5D,QAAI,GAAG,UAAU,yBAAyB;AACxC,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,WAAO,OAAO,QAAQ;AAAA,MACpB;AAAA,MACA,aAAa,QAAQ,oBAAoB,QAAQ;AAAA,IACnD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,oBACE,KACA,WACA,YACQ;AAER,QAAI,CAAC,OAAO,IAAI,WAAW,GAAG;AAC5B,YAAM,IAAI,MAAM,kBAAkB;AAAA,IACpC;AAEA,QAAI,IAAI,KAAK,CAAC,OAAO,GAAG,UAAU,uBAAuB,GAAG;AAC1D,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AAEA,QAAI,YAAY,IAAI,QAAQ;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,IAAI,WAAW,GAAG;AACpB,aAAO,KAAK,qBAAqB,IAAI,CAAC,GAAG,UAAU;AAAA,IACrD;AAEA,UAAM,YAAY,CAAC,GAAG,GAAG,EAAE,KAAK,OAAO,OAAO;AAE9C,aAAS,IAAI,GAAG,IAAI,UAAU,SAAS,GAAG,EAAE,GAAG;AAC7C,UAAI,UAAU,CAAC,EAAE,OAAO,UAAU,IAAI,CAAC,CAAC,GAAG;AACzC,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAAA,IACF;AACA,UAAM,iBAAiB,CAAC,UAAU,CAAC,GAAG,QAAQ,WAAW;AACzD,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,qBAAe,KAAK,UAAU,CAAC,CAAC;AAChC,qBAAe,KAAK,QAAQ,cAAc;AAAA,IAC5C;AACA,mBAAe,KAAK,OAAO,OAAO,OAAO,SAAS,CAAC;AACnD,QAAI,YAAY;AACd,qBAAe,KAAK,QAAQ,iBAAiB;AAAA,IAC/C,OAAO;AACL,qBAAe,KAAK,QAAQ,WAAW;AAAA,IACzC;AACA,WAAO,OAAO,QAAQ,cAAc;AAAA,EACtC;AACF;;;ACtTA;AAAA,EACE,QAAAC;AAAA,EAAM,eAAAC;AAAA,EAAuB,YAAAC;AAAA,EAAU,UAAAC;AAAA,EAAQ,WAAAC;AAAA,EAAS,WAAAC;AAAA,OACnD;;;ACFA,IAAM,eAAe;;;ACA5B,SAAS,UAAUC,sBAAqB;;;ACCjC,IAAM,qBAAqB;AAE3B,IAAM,oBAAoB;AAE1B,IAAM,kBAAkB;AAIxB,IAAM,oCAAoC;AAE1C,IAAM,0BAA0B;AAEhC,IAAM,sCAAsC;AAE5C,IAAM,6BAA6B;AAEnC,IAAM,0BAA0B;AAEhC,IAAM,kCAAkC;AAExC,IAAM,8BAA8B;AAGpC,IAAM,iCAAiC;;;ACxB9C,SAAS,UAAU,eAAe,WAAAC,UAAS,YAAAC,iBAAgB;AAUpD,IAAM,cAAc,CAACC,YAA4B;AACtD,QAAM,aAAa,cAAc,UAAUA,OAAM;AACjD,SAAO,CAAC,CAAC,cAAc,WAAW,CAAC,MAAMC,SAAQ;AACnD;AAQO,IAAM,uBAAuB,CAACD,YAA2B;AAG9D,MAAI;AACF,UAAM,EAAE,SAAS,cAAc,IAAIE,UAAS,OAAO;AAAA,MACjD,QAAQF;AAAA,IACV,CAAC;AACD,QAAI,eAAe;AACjB,aAAO;AAAA,IACT;AAAA,EAEF,SAAS,OAAO;AAAA,EAAC;AAGjB,MAAI;AACF,UAAM,EAAE,SAAS,YAAY,IAAIE,UAAS,KAAK;AAAA,MAC7C,QAAQF;AAAA,IACV,CAAC;AACD,QAAI,aAAa;AACf,aAAO;AAAA,IACT;AAAA,EAEF,SAAS,OAAO;AAAA,EAAC;AAEjB,SAAO;AACT;AAQO,IAAM,+BAA+B,MAAc;AACxD,SAAO;AACT;AAQO,IAAM,gBAAgB,CAAC,eAA+B;AAC3D,SAAO,WAAW,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,OAAO,CAAC;AAC7D;;;AF3BO,IAAM,gCAAgC,CAC3C,gBACA,eACA,SACA,YAIG;AACH,MAAI,eAAe,WAAW,GAAG;AAC/B,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AAEA,QAAM,aAAa,eAAe,OAAO,CAAC,SAAS;AACjD,UAAMG,UAAS,OAAO,KAAK,KAAK,cAAc,KAAK;AACnD,WAAO,CAAC,CAACC,eAAc,UAAUD,OAAM;AAAA,EACzC,CAAC;AAED,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAGA,QAAM,cAAc,WAAW,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAE/D,QAAM,gBAAwB,CAAC;AAC/B,MAAI,mBAAmB;AACvB,MAAI,eAAe;AAEnB,aAAW,QAAQ,aAAa;AAC9B,kBAAc,KAAK,IAAI;AACvB,wBAAoB,KAAK;AAGzB,UAAM,gBAAgB,iBAAiB,eAAe,OAAO;AAC7D,mBAAe,gBAAgB,UAAU,qBAAqB,OAAO;AAGrE,QAAI,oBAAoB,gBAAgB,gBAAgB,cAAc;AACpE,sBAAgB,6BAA6B,IAAI;AAAA,IACnD;AACA,QAAI,oBAAoB,gBAAgB,cAAc;AACpD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,mBAAmB,gBAAgB,cAAc;AACnD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,KAAK;AAAA,EACP;AACF;AAgBO,IAAM,0CAA0C,CACrD,gBACA,SACA,YAIG;AAEH,MAAI,eAAe,WAAW,GAAG;AAC/B,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AAIA,QAAM,aAAa,eAAe,OAAO,CAAC,SAAS;AACjD,UAAMA,UAAS,OAAO,KAAK,KAAK,cAAc,KAAK;AACnD,UAAM,mBAAmBC,eAAc,UAAUD,OAAM;AACvD,WAAO,oBAAoB,iBAAiB,SAAS;AAAA,EACvD,CAAC;AAED,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAKA,QAAM,cAAc,WAAW,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAG/D,aAAW,QAAQ,aAAa;AAQ9B,UAAM,gBAAgB;AAAA,MACpB,CAAC,IAAI;AAAA,MACL;AAAA,IACF,IAAI;AAGJ,QAAI,eAAe,gBAAgB,UAAU,qBAAqB,OAAO;AAQzE,QAAI,KAAK,SAAS,cAAc;AAI9B,UAAI,KAAK,QAAQ,eAAe,cAAc;AAE5C,wBAAgB,6BAA6B,IAAI;AAAA,MACnD;AAEA,UAAI,KAAK,SAAS,cAAc;AAC9B,eAAO;AAAA,UACL,cAAc;AAAA,UACd,KAAK;AAAA,QACP;AAAA,MACF;AAAA,IAGF;AAAA,EACF;AAGA,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAaO,IAAM,mBAAmB,CAAC,YAA4B;AAC3D,QAAM,YAAY;AAClB,QAAM,aAAa,6BAA6B;AAChD,SACE,WACG,YACC,aACA,0BACA,2BACJ,qBAAqB,OAAO;AAEhC;AAcA,IAAM,mBAAmB,CACvB,YACA,YACW;AAEX,QAAM,YAAY,WAAW,OAAO,CAAC,KAAa,MAAoB;AACpE,UAAMA,UAAS,OAAO,KAAK,EAAE,cAAc,KAAK;AAChD,UAAM,mBAAmBC,eAAc,UAAUD,OAAM;AACvD,QAAI,CAAC,kBAAkB;AAErB,aAAO;AAAA,IACT;AACA,WAAO,MAAM,qBAAqBA,OAAM;AAAA,EAC1C,GAAG,CAAC;AAGJ,QAAM,aAAa,QAAQ,OAAO,CAAC,KAAK,WAAmB;AACzD,QAAI,YAAY,OAAO,YAAY,GAAG;AACpC,aACE,MACA,OAAO,aAAa,SACpB,8BACA;AAAA,IAEJ;AACA,WAAO,MAAM;AAAA,EACf,GAAG,CAAC;AAEJ,SAAO,YAAY,aAAa;AAClC;AAgBA,IAAM,uBAAuB,CAAC,YAA4B;AACxD,SAAO,WAAW,kCACd,sCACA;AACN;;;AGhRO,IAAM,mBAAmB;AAEzB,IAAM,sBAAsB;;;ALsBnC,IAAM,kCAAkC;AACxC,IAAM,+BAA+B;AAoC9B,SAAS,mBACd,SAMA,QACA,eACA,YACA,SACA,SACA,YACmB;AAEnB,MAAI,UAAU,KAAK,WAAW,GAAG;AAC/B,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAGA,MAAI,CAAC,sBAAsB,eAAe,OAAO,GAAG;AAClD,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAGA,QAAM,iBAAiB,+BAA+B,SAAS,SAAS,MAAM;AAC9E,QAAM,EAAE,eAAe,IAAI,IAAI;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,KAAK,IAAIE,aAAY;AAC3B,KAAG,UAAU;AAEb,WAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,EAAE,GAAG;AAC7C,UAAM,QAAQ,cAAc,CAAC;AAC7B,OAAG;AAAA,MACD,oBAAoB,MAAM,IAAI;AAAA,MAC9B,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,QAAQ,CAAC,MAAM;AAC5B,OAAG,UAAU,EAAE,cAAc,EAAE,KAAK;AAAA,EACtC,CAAC;AAGD,QAAM,YAAY,cAAc,aAAa;AAE7C,MAAI,aAAa,SAAS,OAAO,cAAc;AAC7C,OAAG;AAAA,MACDC,SAAQ,eAAe,eAAe,OAAO;AAAA,MAC7C,aAAa,SAAS;AAAA,IACxB;AAAA,EACF;AAIA,MAAI,YAAY;AACd,QAAI,cAAc,iCAAiC;AACjD,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AACA,OAAG,WAAW;AAAA,EAChB;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,EACF;AACF;AAwBO,SAAS,4BACd,SACA,SAKA,QACA,eACA,SACA,YACA,uBAUA;AAEA,MAAI,UAAU,KAAK,WAAW,GAAG;AAC/B,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D,WAAW,CAAC,sBAAsB,eAAe,OAAO,GAAG;AACzD,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAKA,QAAM,4BAA4B;AAAA,IAChC,sBAAsB;AAAA,IAAS;AAAA,EACjC;AAKA,QAAM,6BAA6B;AAAA,IACjC,sBAAsB;AAAA,IACtB,0BAA0B;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,wBAAwB,sBAAsB,UAAU,KAC5D,0BACF,EAAE;AAKF,MAAI,WAAW,uBAAuB;AACpC,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAIA,QAAM,iBAAiB;AAAA,IACrB;AAAA,IAAS;AAAA,IAAS;AAAA,EACpB;AAIA,QAAM,EAAE,cAAc,IAAI,IAAI;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,KAAK,IAAID,aAAY;AAC3B,KAAG,UAAU;AAIb,KAAG;AAAA,IACD,sBAAsB,UAAU,QAAQ;AAAA,IACxC;AAAA,IACA;AAAA,EACF;AAIA,KAAG;AAAA,IACD,oBAAoB,aAAa,IAAI;AAAA,IACrC,aAAa;AAAA,IACb;AAAA,EACF;AAIA,iBAAe,QAAQ,CAAC,MAAM;AAC5B,OAAG,UAAU,EAAE,cAAc,EAAE,KAAK;AAAA,EACtC,CAAC;AAID,MAAI,aAAa,QAAQ,MAAM,cAAc;AAC3C,OAAG;AAAA,MACDC,SAAQ,eAAe,eAAe,OAAO;AAAA,MAC7C,aAAa,QAAQ;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IACA,aAAa;AAAA,EACf;AACF;AA0BO,SAAS,iCACd,SAIA,aACA,mBACA,SACA,SACY;AACZ,QAAM,aAAsB;AAAA,IAC1B;AAAA,MACE,QAAQ,QAAQ;AAAA,IAClB;AAAA,IACA,EAAE,QAAQ,QAAQ,wBAAwB;AAAA,EAC5C;AAEA,SAAO;AAAA,IACL;AAAA,MACE,gBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,EACF;AACF;AA6BO,SAAS,oCACd,SAKA,IACA,mBACA,SACA,SACA,cAAsB,GACV;AACZ,QAAM,aAAsB;AAAA,IAC1B;AAAA,MACE,QAAQ,QAAQ;AAAA,IAClB;AAAA,IACA,CAAC,EAAE,QAAQ,QAAQ,gBAAgB,GAAG,EAAE,QAAQ,QAAQ,eAAe,CAAC;AAAA,EAC1E;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAiBO,SAAS,4BACd,SAGA,YACA,mBACA,SACA,SACA,aACY;AACZ,QAAM,aAAsB,EAAE,QAAQ,QAAQ,wBAAwB;AAEtE,SAAO;AAAA,IACL;AAAA,MACE,gBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAIA,SAAS,sBACP,SAGA,YACA,IACA,mBACA,SACA,SACA,cAAsB,GACV;AAEZ,MAAI,WAAW,GAAG;AAChB,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAGA,MAAI,cAAc,GAAG;AACnB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAGA,QAAM,eAAe;AACrB,QAAM,aAAaC,QAAO,UAAU,QAAQ,cAAc;AAE1D,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAEA,MAAI,WAAW;AAGf,MAAI,OAAO,WAAW,YAAY,MAAM,UAAU;AAChD,UAAM,aAAa,WAAW,YAAY;AAC1C,eAAWA,QAAO,OAAO,OAAO,UAAU;AAAA,EAC5C,OAAO;AAEL,UAAM,OAAO,WAAW,YAAY,IAAI;AACxC,eAAW,SAAS,IAAI,KAAK;AAAA,EAC/B;AAEA,QAAM,SAAS;AAAA,IACb,QAAQ,QAAQ;AAAA,IAChB,eAAe;AAAA,EACjB;AAEA,QAAM,OAAOC,UAAS,KAAK;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB;AAAA,IACpB,aAAa,OAAO;AAAA,IACpB,QAAQ,OAAO;AAAA,IACf,cAAc,KAAK,QAAS,KAAK,QAAS,SAAS,CAAC;AAAA,EACtD;AAEA,QAAM,OAAO,IAAIC,MAAK,EAAE,QAAQ,CAAC;AAIjC,OAAK,WAAW,mBAAmB;AAEnC,OAAK,SAAS;AAAA,IACZ,MAAM,GAAG,QAAQ;AAAA,IACjB,OAAO;AAAA,IACP,gBAAgB;AAAA,IAChB,aAAa;AAAA,MACX,OAAO,GAAG,KAAK,WAAW,EAAE;AAAA,MAC5B,QAAQ,GAAG,KAAK,WAAW,EAAE;AAAA,IAC/B;AAAA,IACA,eAAe,CAAC,aAAa;AAAA,IAC7B,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,eAAe,iBAAiB,OAAO;AAC7C,QAAM,cAAc,GAAG,KAAK,WAAW,EAAE,QAAQ;AACjD,MAAI,cAAc,GAAG;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,cAAc,cAAc;AAC9B,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,OAAK,UAAU;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAID,OAAK,YAAY,CAAC;AAElB,SAAO;AAAA,IACL;AAAA,IACA,KAAK;AAAA,EACP;AACF;AAkCO,SAAS,iCACd,SAMAC,qBACA,qBACA,cACA,YACA,SACA,cAAsB,GACN;AAChB,QAAM,qBAA8B;AAAA,IAClC;AAAA,MACE,QAAQ,QAAQ;AAAA,IAClB;AAAA,IACA,CAAC,EAAE,QAAQ,QAAQ,gBAAgB,GAAG,EAAE,QAAQ,QAAQ,eAAe,CAAC;AAAA,EAC1E;AACA,SAAO;AAAA,IACL;AAAA,MACE,yBAAyB,QAAQ;AAAA,MACjC,gBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA;AAAA,IACAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAoBO,SAAS,8BACd,SAIA,aACA,qBACA,cACA,oBACA,SACgB;AAChB,QAAM,sBAA+B;AAAA,IACnC;AAAA,MACE,QAAQ,QAAQ;AAAA,IAClB;AAAA,IACA;AAAA,MACE,QAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,MACE,yBAAyB,QAAQ;AAAA,MACjC,gBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,EACF;AACF;AAqBA,SAAS,oBACP,SAIA,YACA,aACA,qBACA,cACA,YACA,SACA,cAAsB,GAGtB;AAEA,MAAI,gBAAgB,KAAK,gBAAgB,GAAG;AAC1C,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AAEA,iBAAe,WAAW,aAAa,QAAQ,4BAA4B,CAAC;AAE5E,MAAI,cAAc,KAAK,CAAC,OAAO,UAAU,UAAU,GAAG;AACpD,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AAGA,MAAI,cAAc,KAAK,CAAC,OAAO,UAAU,WAAW,GAAG;AACrD,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAGA,MAAI,CAAC,YAAY,KAAK,WAAW,GAAG;AAClC,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAEA,QAAM,SAAS;AAAA,IACb,QAAQ,QAAQ;AAAA,IAChB,eAAe;AAAA,EACjB;AAEA,QAAM,OAAOF,UAAS,KAAK;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB;AAAA,IACpB,aAAa,OAAO;AAAA,IACpB,QAAQ,OAAO;AAAA,IACf,cAAc,KAAK,QAAS,KAAK,QAAS,SAAS,CAAC;AAAA,EACtD;AAEA,QAAM,gBAAgB,YAAY,KAAK,WAAW,EAAE;AAGpD,QAAM,iBAAiB,KAAK,MAAM,gBAAgB,YAAY;AAG9D,QAAM,iBAAiB,OAAO,KAAK,qBAAqB,KAAK;AAI7D,MAAIG,SAAQ,aAAa,eAAe,CAAC,GAAG;AAC1C,QAAI,kBAAkB,cAAc;AAClC,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,YAAY,gBAAgB,iBAAiB;AACnD,MAAI,aAAa,cAAc;AAC7B,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAEA,QAAM,OAAO,IAAIF,MAAK,EAAE,QAAQ,CAAC;AACjC,OAAK,WAAW,mBAAmB;AAEnC,OAAK,SAAS;AAAA,IACZ,MAAM,YAAY,QAAQ;AAAA,IAC1B,OAAO;AAAA,IACP,gBAAgB;AAAA,IAChB,aAAa;AAAA,MACX,OAAO;AAAA,MACP,QAAQ,YAAY,KAAK,WAAW,EAAE;AAAA,IACxC;AAAA,IACA,eAAe,CAAC,aAAa;AAAA;AAAA,IAE7B,UAAU;AAAA,EACZ,CAAC;AAGD,OAAK,UAAU;AAAA,IACb,QAAQ;AAAA,IACR,OAAO;AAAA,EACT,CAAC;AAGD,QAAM,eAAeD,UAAS,KAAK;AAAA,IACjC;AAAA,IACA,YAAY,EAAE,QAAQ,QAAQ,wBAAwB;AAAA,IACtD;AAAA,EACF,CAAC;AAED,OAAK,UAAU;AAAA,IACb,SAAS,aAAa;AAAA,IACtB,OAAO;AAAA,EACT,CAAC;AAID,OAAK,YAAY,CAAC;AAElB,SAAO,EAAE,KAAK;AAChB;AAEO,SAAS,qBACd,SAIA,WACA,cACA,SACA,cAAsB,GACH;AAEnB,MAAI,gBAAgB,GAAG;AACrB,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAGA,MAAI,cAAc,GAAG;AACnB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,QAAM,KAAK,IAAIH,aAAY;AAC3B,KAAG,UAAU;AAEb,KAAG;AAAA,IACD,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA;AAAA;AAAA,EACF;AAEA,QAAM,sBAAsB,0BAA0B,SAAS,OAAO;AAEtE,QAAM,cAAc,UAAU,KAAK,WAAW,EAAE,QAAQ;AACxD,MAAI,cAAc,cAAc;AAC9B,UAAM,IAAI,MAAM,gEAAgE;AAAA,EAClF;AAEA,MAAI,CAAC,oBAAoB,eAAe;AACtC,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AACA,KAAG;AAAA,IACD,oBAAoB;AAAA,IACpB;AAAA,EACF;AAIA,KAAG,WAAW;AAEd,SAAO;AAAA,IACL,aAAa;AAAA,IACb,KAAK;AAAA,EACP;AACF;AAKO,IAAM,wBAAwB,CACnC,iBACA,iBACA,cACA,mBACG;AACH,MAAI,aAAa,SAAS,gBAAgB;AACxC,UAAM,IAAI;AAAA,MACR,6CAA6C,cAAc,UACjD,aAAa,MAAM;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,uBAAuB,aAAa,OAAO,CAAC,QAAQ;AACxD,UAAM,cAAc,OAAO,KAAK,IAAI,UAAU,KAAK;AACnD,WAAO,gBAAgB,KAAK,cAAY,SAAS,OAAO,WAAW,CAAC;AAAA,EACtE,CAAC;AAED,MAAI,qBAAqB,SAAS,gBAAgB;AAChD,UAAM,IAAI;AAAA,MACR,mDAAmD,cAAc,UACvD,qBAAqB,MAAM;AAAA,IACvC;AAAA,EACF;AAMA,QAAM,sBAAsB,aACzB,MAAM,GAAG,cAAc,EACvB,IAAI,CAAC,SAAS;AAAA,IACb,UAAU,OAAO,KAAK,IAAI,UAAU,KAAK;AAAA,IACzC,QAAQ,OAAO,KAAK,IAAI,QAAQ,KAAK;AAAA,EACvC,EAAE;AAGJ,QAAM,wBAAwB,CAAC,GAAG,eAAe,EAC9C,KAAK,OAAO,OAAO,EACnB,QAAQ;AAEX,QAAM,uBAAuB,sBAAsB,IAAI,CAAC,aAAa;AAGnE,UAAM,cAAc,oBAAoB;AAAA,MACtC,CAAC,QAAQ,IAAI,SAAS,QAAQ,QAAQ,MAAM;AAAA,IAC9C;AACA,WAAO,aAAa,UAAU,OAAO,MAAM,CAAC;AAAA,EAC9C,CAAC;AAED,SAAO,CAAC,GAAG,sBAAsB,GAAG,eAAe;AACrD;;;AM33BO,IAAM,6BAA6B;;;ACF1C,SAAS,kBAAkB;AAQpB,IAAM,wBAAwB,CAACO,aAA6B;AACjE,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,WAAWA,QAAO;AACrC,WAAO,WAAW;AAAA,EACpB,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;;;ACAO,IAAM,iCAAiC,CAC5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAOG;AACH,MAAI,wBAAwB,GAAG;AAC7B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,cAAc,WAAW,WAAW,GAAG;AAC1C,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,kBAAkB,CAAC,sBAAsB,cAAc,GAAG;AAC5D,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAa,qBAAqB,qBAAqB,kBAAkB;AAC3E,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,aAAa;AAChC,QAAM,cAAc,qBAAqB;AAIzC,QAAM,qBAAqB,YAAY,OAAO,YAAU,CAAC,WAAW,SAAS,MAAM,CAAC;AAEpF,MAAI,mBAAmB,SAAS,GAAG;AACjC,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,2CACqC,mBAAmB,KAAK,IAAI,CAAC;AAAA,IACpE;AAAA,EACF;AACF;AAYO,IAAM,6BAA6B,CACxC,kBACA,UACA,QACA,YACA,YACG;AACH,MACE,mBAAmB,OAAO,uBAC1B,mBAAmB,OAAO,qBAC1B;AACA,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,MACE,WAAW,OAAO,wBAClB,WAAW,OAAO,sBAClB;AACA,UAAM,IAAI,kDAA6C,kBAAkB;AAAA,EAC3E;AAEA,MAAI,WAAW,UAAU,GAAG;AAC1B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,WAAW,GAAG;AAChB,UAAM,IAAI,kDAA6C,kBAAkB;AAAA,EAC3E;AACF;AASO,IAAM,iBAAiB,CAAC,WAA0B;AAEvD,MAAI,OAAO,mBAAmB,UAAU,GAAG;AACzC,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,mBAAmB,SAAS,OAAO,gBAAgB;AAC5D,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,SAAO,mBAAmB,QAAQ,CAAC,OAAO;AACxC,QAAI,CAAC,wBAAwB,EAAE,GAAG;AAChC,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,OAAO,iBAAiB,GAAG;AAC7B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,mBAAmB,GAAG;AAC/B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,sBAAsB,OAAO,qBAAqB;AAC3D,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MACE,OAAO,sBACP,OAAO,kBAAkB,4BACzB;AACA,UAAM,IAAI;AAAA;AAAA,MAER,8DAA8D,0BAA0B;AAAA,IAC1F;AAAA,EACF;AACA,MAAI,OAAO,uBAAuB,OAAO,sBAAsB;AAC7D,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,wBAAwB,GAAG;AACpC,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,kBAAkB,GAAG;AAC9B,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,UAAU;AACnB,QAAI,OAAO,SAAS,gBAAgB,GAAG;AACrC,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,SAAS,eAAe,GAAG;AACpC,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,SAAS,oBAAoB,UAAU,GAAG;AACnD,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,SAAS,uBAAuB,GAAG;AAC5C,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AASO,IAAM,0BAA0B,CACrC,iBACA,WACG;AACH,MACE,kBAAkB,OAAO,wBACzB,kBAAkB,OAAO,sBACzB;AACA,UAAM,IAAI;AAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;AAgBO,IAAM,yCAAyC,CACpD,4BACA,8BACG;AACH,QAAM,0BAA0B,2BAA2B;AAC3D,QAAM,yBAAyB,0BAA0B;AACzD,QAAM,iBAAiB,2BAA2B;AAGlD,QAAM,wBAAwB,wBAAwB;AAAA,IACpD,gBAAc,uBAAuB,SAAS,UAAU;AAAA,EAC1D,EAAE;AAEF,MAAI,wBAAwB,gBAAgB;AAC1C,UAAM,IAAI;AAAA;AAAA,MAER,qEACa,cAAc,gBAAgB,qBAAqB;AAAA,IAElE;AAAA,EACF;AACF;;;ACnPO,IAAM,UAAN,MAAM,SAAQ;AAAA,EAOnB,YACE,SACA,YACA,QACA,+BACA,iBACA;AAEA,QAAI,CAAC,sBAAsB,WAAW,SAAS,OAAO,GAAG;AACvD,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,wBAAwB,WAAW,mBAAmB,GAAG;AAC5D,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,QACE,8BAA8B,WAAW,KACzC,CAAC,8BAA8B,MAAM,uBAAuB,GAC5D;AACA,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,mBAAe,MAAM;AACrB,4BAAwB,iBAAiB,MAAM;AAE/C,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,SAAS;AACd,SAAK,gCAAgC;AACrC,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAA+B;AAC7B,UAAM,EAAE,gBAAgB,oBAAoB,cAAc,IAAI,KAAK;AAEnE,QAAI;AACJ,QAAI;AACF,0BAAoB,IAAI;AAAA,QACtB,OAAO,KAAK,KAAK,WAAW,qBAAqB,KAAK;AAAA,QACtD,KAAK,8BAA8B,IAAI,CAAC,OAAO,OAAO,KAAK,IAAI,KAAK,CAAC;AAAA,QACrE,UAAU,kBAAkB;AAAA,QAC5B;AAAA,QACA,KAAK;AAAA,QACL;AAAA,MACF;AAAA,IACF,SAAS,OAAgB;AACvB,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,gBAAU,kBAAkB,aAAa;AAAA,IAC3C,SAAS,OAAgB;AACvB,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaO,yBACL,kBACA,YACA,SACmB;AACnB;AAAA,MACE;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,aAAa;AAElC,QAAI;AACF,YAAM,EAAE,aAAa,IAAI,IAAI;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,KAAK,WAAW;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,QACL;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAgB;AACvB,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoCO,kCACL,kBACA,YACA,SACA,4BACA,uBASA;AACA;AAAA,MACE;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AACA;AAAA,MACE;AAAA,MACA,KAAK;AAAA,IACP;AAKA,UAAM,kBAAkB,IAAI;AAAA,MAC1B,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,sBAAsB,aAAa;AAAA,MACnC,sBAAsB,aAAa;AAAA,IACrC;AAMA,UAAM;AAAA,MACJ,aAAa;AAAA,MACb,KAAK;AAAA,MACL;AAAA,IACF,IAAI;AAAA,MACF,KAAK;AAAA,MACL,KAAK,aAAa;AAAA,MAClB;AAAA,MACA,KAAK,WAAW;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW,sBAAsB;AAAA,QACjC,SAAS,gBAAgB,aAAa;AAAA,MACxC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,aAAa;AAAA,MACb,KAAK;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,cAAc,WAAwB,YAA0B;AAErE,UAAM,UAAU,KAAK,aAAa;AAClC,UAAM,oBAAoB,wBAAwB,SAAS,KAAK,OAAO;AACvE;AAAA,MACE;AAAA,MACA,kBAAkB;AAAA,MAClB,KAAK;AAAA,IACP;AAEA,WAAO;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL;AAAA,MACA,UAAU,KAAK,WAAW,SAAS,KAAK,OAAO,IAC3C,OAAO,KAAK,KAAK,WAAW,qBAAqB,KAAK,IACtD;AAAA,IACN;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBO,uBACL,oBACA,YACA,4BACA,uBAOM;AAKN,UAAM,kBAAkB,IAAI;AAAA,MAC1B,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,sBAAsB,aAAa;AAAA,MACnC,sBAAsB,aAAa;AAAA,IACrC;AAGA,UAAM,kBAAkB,gBAAgB,aAAa;AACrD,UAAM,EAAE,cAAc,IAAI,wBAAwB,iBAAiB,KAAK,OAAO;AAI/E,UAAM,6BAA6B;AAAA,MACjC,sBAAsB;AAAA,MACtB;AAAA,MACA,KAAK;AAAA,IACP;AAMA,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,QACE,WAAW,sBAAsB;AAAA,QACjC,aAAa;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,KAAK,WAAW,SAAS,KAAK,OAAO,IAC3C,OAAO,KAAK,KAAK,WAAW,qBAAqB,KAAK,IACtD;AAAA,IACN;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,2BAA2B,WAA2C;AAE3E,UAAM,UAAU,KAAK,aAAa;AAClC,UAAM,EAAE,cAAc,IAAI,wBAAwB,SAAS,KAAK,OAAO;AAEvE,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAEA,QAAI;AACF,YAAM,EAAE,YAAY,IAAI;AAAA,QACtB;AAAA,QACA;AAAA,QACA,KAAK,OAAO;AAAA,QACZ,KAAK;AAAA,QACL;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,QACA,KAAK,KAAK,OAAO;AAAA,MACnB;AAAA,IACF,SAAS,OAAO;AACd,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,gBACL,aACA,WACM;AACN,WAAO;AAAA,MACL,KAAK,aAAa;AAAA,MAClB;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeO,uCACL,iBACA,SACY;AAEZ,UAAM,UAAU,KAAK,aAAa;AAGlC,QAAI;AACF,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,KAAK,WAAW;AAAA,QAChB,KAAK;AAAA,QACL;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,iCACL,WACA,SACY;AAEZ,UAAM,UAAU,KAAK,aAAa;AAClC,UAAM,EAAE,cAAc,IAAI,wBAAwB,SAAS,KAAK,OAAO;AAEvE,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAGA,QAAI;AACF,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,KAAK,WAAW;AAAA,QAChB,KAAK;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,gCAAgC,WAAoC;AACzE,QAAI,CAAC,KAAK,OAAO,UAAU;AACzB,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAGA,UAAM,UAAU,KAAK,aAAa;AAGlC,UAAM,EAAE,cAAc,IAAI,wBAAwB,SAAS,KAAK,OAAO;AAGvE,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAGA,QAAI;AACF,YAAM,EAAE,KAAK,IAAI;AAAA,QACf;AAAA,QACA;AAAA,QACA,KAAK,OAAO,SAAS;AAAA,QACrB,KAAK,OAAO,SAAS;AAAA,QACrB,KAAK,OAAO,SAAS;AAAA,QACrB,KAAK;AAAA,QACL;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,QACA,KAAK,KAAK,OAAO,SAAS;AAAA,MAC5B;AAAA,IACF,SAAS,OAAO;AACd,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,kCACL,aACY;AACZ,QAAI,CAAC,KAAK,OAAO,UAAU;AACzB,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,aAAa;AAGlC,QAAI;AACF,YAAM,EAAE,KAAK,IAAI;AAAA,QACf;AAAA,QACA;AAAA,QACA,KAAK,OAAO,SAAS;AAAA,QACrB,KAAK,OAAO,SAAS;AAAA,QACrB,KAAK,OAAO,SAAS;AAAA,QACrB,KAAK;AAAA,MACP;AACA,aAAO;AAAA,QACL;AAAA,QACA,KAAK,KAAK,OAAO,SAAS;AAAA,MAC5B;AAAA,IACF,SAAS,OAAO;AACd,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,2BACL,YACA,SACY;AAEZ,UAAM,UAAU,KAAK,aAAa;AAClC,UAAM,qBAAqB,qBAAqB,SAAS,KAAK,OAAO;AAGrE,UAAM,sBAAsB;AAAA,MAC1B;AAAA,MACA,mBAAmB;AAAA,MACnB,KAAK;AAAA,IACP;AAGA,QAAI;AACF,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,KAAK,WAAW;AAAA,QAChB,KAAK;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACxoBA,SAAS,eAAe,YAAY,oBAAoB;AACxD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,QAAAC,OAAM,eAAAC,oBAA6B;;;ACNrC,IAAM,6BAA6B;AAAA,EACxC,wBAAwB;AAAA,EACxB,mBAAmB;AACrB;;;ACEO,IAAM,gBAAgB,CAAC,WAAmC;AAC/D,QAAM,eAAe,IAAI,WAAW,MAAM;AAC1C,MAAI,aAAa,SAAS,EAAG,QAAO;AACpC,WAAS,IAAI,GAAG,IAAI,aAAa,SAAS,GAAG,IAAI,aAAa,SAAS,GAAG,KAAK,KAAK;AAClF,QAAI,MAAM,aAAa,CAAC;AACxB,iBAAa,CAAC,IAAI,aAAa,CAAC;AAChC,iBAAa,CAAC,IAAI;AAAA,EACpB;AACA,SAAO;AACT;;;ACdA,SAAS,cAAc;;;ACIhB,IAAM,yBAAyB;;;ADO/B,SAAS,uBACd,SACA,oBAA4B,GACpB;AAUR,QAAM,gBAAgB,cAAc,iBAAiB,eAAe,OAAO,IAAI,sBAAsB;AACrG,SAAO,OAAO,OAAO,KAAK,eAAe,MAAM,CAAC,EAAE,SAAS,KAAK;AAClE;AAYO,SAAS,gBACd,eACA,eACA,SACA,eACQ;AAGR,MACE,YAAY,UACZ,eAAe,kBAAkB,UACjC,cAAc,YAAY,UAC1B,kBAAkB,UAClB,iBAAiB,cAAc,eAC/B;AACA,UAAM,cAAc,uBAAuB,SAAS,cAAc,OAAO;AACzE,WAAO,cAAc;AAAA,EACvB;AAEA,SAAO;AACT;;;AElDO,IAAM,6BAA6B,CACxC,QACA,0BACkB;AAElB,QAAM,eAAe,CAAC,GAAG,qBAAqB,EAAE;AAAA,IAC9C,CAAC,GAAG,MAAM,EAAE,sBAAsB,EAAE;AAAA,EACtC;AAGA,QAAM,SAAS,aAAa;AAAA,IAC1B,CAAC,MAAM,UAAU,EAAE;AAAA,EACrB;AACA,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,uCAAuC,MAAM,EAAE;AAC5E,SAAO;AACT;AAQO,IAAM,2BAA2B,CACtC,SACA,kBACkB;AAClB,QAAM,SAAS,cAAc,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO;AAC9D,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,wCAAwC,OAAO,EAAE;AAC9E,SAAO;AACT;;;ALJO,IAAM,2BAAN,MAA+B;AAAA,EAGpC,YACY,SACA,eACA,aACA,iBACA,IACV,eACA;AANU;AACA;AACA;AACA;AACA;AAGV,SAAK,UAAU;AAEf,QAAI,cAAc,WAAW,GAAG;AAC9B,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,SAAK,gBAAgB;AAErB,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,uCACJ,eACA,cACA,qBACA,YACA,SACA,gBAIC;AACD,QAAI,wBAAwB,GAAG;AAC7B,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,QAAI,CAAC,sBAAsB,cAAc,GAAG;AAC1C,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAGA,UAAM,SAAS,2BAA2B,qBAAqB,KAAK,aAAa;AAEjF,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAGA,UAAM,EAAE,YAAY,IAAI,QAAQ,yBAAyB,aAAa,kBAAkB,YAAY,OAAO;AAG3G,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,qBAAqB;AAAA,MACjC,MAAM;AAAA,IACR,CAAC;AAED,WAAO;AAAA,MACL,iBAAiB,MAAM,KAAK,gBAAgB,gBAAgB,GAAG;AAAA,MAC/D,WAAW;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,+CACJ,eACA,cACA,qBACA,YACA,SACA,gBAEA,uBAQC;AAED,mCAA+B;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA,sBAAsB,sBAAsB;AAAA,MAC5C;AAAA,IACF,CAAC;AAED,UAAM,SAAS,2BAA2B,qBAAqB,KAAK,aAAa;AAEjF,UAAM,6BAA6B,yBAAyB,sBAAsB,cAAc,KAAK,aAAa;AAElH,UAAM,kBAAkB,IAAI;AAAA,MAC1B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,aAAa,oBAAoB,YAAY,IAAI,gBAAgB;AAAA,MACvE,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,kBAAY,MAAM,KAAK,YAAY,kBAAkB,YAAY,IAAI;AAAA,IACvE,SAAS,OAAO;AACd,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QAEA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,yBAAyB;AAAA,UACvB,mBAAmB,sBAAsB;AAAA,UACzC,WAAWC,aAAY,QAAQ,SAAS;AAAA,QAC1C;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,qBAAqB;AAAA,MACjC,MAAM;AAAA,IACR,CAAC;AAED,WAAO;AAAA,MACL,iBAAiB,MAAM,KAAK,gBAAgB,gBAAgB,GAAG;AAAA,MAC/D,WAAW;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,+BACE,eACA,qBACA,cACA,YACA,SACA,uBAKQ;AAER,mCAA+B;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA,sBAAsB,sBAAsB;AAAA,IAC9C,CAAC;AAKD,UAAM,SAAS,2BAA2B,qBAAqB,KAAK,aAAa;AAKjF,UAAM,6BAA6B,yBAAyB,sBAAsB,cAAc,KAAK,aAAa;AAKlH,UAAM,kBAAkB,IAAI;AAAA,MAC1B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AACA,UAAM,EAAE,IAAI,IAAI,gBAAgB;AAAA,MAC9B,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,wCACJ,eACA,WACA,iBACA,cACA,gBACA,gBAGC;AAED,UAAM,SAAS,2BAA2B,iBAAiB,KAAK,aAAa;AAE7E,QAAI,CAAC,sBAAsB,cAAc,GAAG;AAC1C,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,kBAAkB,IAAI;AAAA,MAC1B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAGA,UAAM,UAAU,gBAAgB,aAAa;AAC7C,UAAM,oBAAoB,wBAAwB,SAAS,KAAK,OAAO;AAGvE,8BAA0B,WAAW,kBAAkB,eAAe,KAAK,OAAO;AAGlF,UAAM,gBAAgB,MAAM,KAAK;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,gBAAgB,KAAK,kBAAkB,cAAc;AAAA,MACvD;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,uBAAuB;AAAA,MACnC,MAAM;AAAA,IACR,CAAC;AAED,WAAO;AAAA,MACL,iBAAiB,MAAM,KAAK,gBAAgB,gBAAgB,aAAa;AAAA,IAC3E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,sBACE,eACA,qBACA,cACA,YACA,SACQ;AACR,QAAI,wBAAwB,GAAG;AAC7B,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AAEA,UAAM,SAAS,2BAA2B,qBAAqB,KAAK,aAAa;AAEjF,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,KAAK,WAAW,IAAI,QAAQ,yBAAyB,aAAa,kBAAkB,YAAY,OAAO;AAE/G,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,kCACJ,eACA,cACA,mBACA,YACA,sBACsB;AACtB,UAAM,SAAS,yBAAyB,sBAAsB,KAAK,aAAa;AAEhF,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAMC,eAAc,QAAQ,cAAc,mBAAmB,UAAU;AAEvE,UAAM,YAAwB;AAAA,MAC5B;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,mBAAmB,aAAa;AAAA,UAChC,aAAa,OAAO;AAAA,UACpB,mBAAmB,OAAO;AAAA,UAC1B,kBAAkB,OAAO;AAAA,UACzB,iBAAiB,aAAa;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,oBAAoB;AAAA,MAChC,UAAU,cAAc;AAAA,MACxB,mBAAmB,aAAa;AAAA,MAChC,aAAa,OAAO;AAAA,MACpB,mBAAmB,OAAO;AAAA,MAC1B,qBAAqB,OAAO;AAAA,MAC5B,iBAAiB,aAAa;AAAA,MAC9B,MAAM;AAAA,IACR,CAAC;AAED,UAAM,uBAAuB,MAAM,KAAK,YAAY,SAASA,aAAY,MAAM,GAAG;AAAA,MAChF;AAAA,MACA,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAOC,MAAK,QAAQ,oBAAoB,EAAE,mBAAmB;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,MAAM,2CACJ,eACA,cACA,4BACA,YACA,sBACA,uBAKA,oCAIsB;AACtB,mCAA+B;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,sBAAsB,sBAAsB;AAAA,IAC9C,CAAC;AAID,UAAM,SAAS,yBAAyB,sBAAsB,KAAK,aAAa;AAGhF,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAIA,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,iBAAiB,yBAAyB,sBAAsB,cAAc,KAAK,aAAa;AAKtG,UAAMC,wBAAuB,QAAQ;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,UAAM,YAAwB;AAAA,MAC5B;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,mBAAmB,aAAa;AAAA,UAChC,aAAa,OAAO;AAAA,UACpB,mBAAmB,OAAO;AAAA,UAC1B,kBAAkB,OAAO;AAAA,UACzB,iBAAiB,aAAa;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAIA,SAAK,IAAI,KAAK,oBAAoB;AAAA,MAChC,UAAU,cAAc;AAAA,MACxB,mBAAmB,aAAa;AAAA,MAChC,aAAa,OAAO;AAAA,MACpB,mBAAmB,OAAO;AAAA,MAC1B,qBAAqB,OAAO;AAAA,MAC5B,iBAAiB,aAAa;AAAA,MAC9B,MAAM;AAAA,IACR,CAAC;AAKD,UAAM,uBAAuB,MAAM,KAAK,YAAY,SAASA,sBAAqB,MAAM,GAAG;AAAA,MACzF;AAAA,MACA,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,2BAA2BD,MAAK,QAAQ,oBAAoB,EAAE,mBAAmB;AAMvF,QAAI,yBAAyB,MAAM,MAAM,2BAA2B,MAAM,GAAG;AAC3E,YAAM,IAAI,MAAM,qEAAqE;AAAA,IACvF;AAMA,UAAM,kBAAkB,eAAe,mBAAmB,IAAI,CAAC,aAAa,OAAO,KAAK,UAAU,KAAK,CAAC;AAKxG,UAAM,UAAU;AAAA;AAAA;AAAA;AAAA,MAId,yBAAyB,IAAI,CAAC,EAAE;AAAA,MAChC;AAAA,MACA;AAAA,MACA,eAAe;AAAA,IACjB;AAIA,6BAAyB,IAAI,CAAC,EAAE,UAAU;AAE1C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,2CACJ,eACA,cACA,sBACA,WAC4B;AAE5B,UAAM,SAAS,yBAAyB,sBAAsB,KAAK,aAAa;AAEhF,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,aAAa,aAAa,IAAI,IAAI,QAAQ,2BAA2B,SAAS;AAEtF,UAAM,OAAO,QAAQ,gBAAgB,aAAa,SAAS;AAE3D,UAAM,YAAwB;AAAA,MAC5B;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,mBAAmB,aAAa;AAAA,UAChC,aAAa,OAAO;AAAA,UACpB,mBAAmB,OAAO;AAAA,UAC1B,kBAAkB,OAAO;AAAA,UACzB,iBAAiB,aAAa;AAAA,QAChC;AAAA,MACF;AAAA,MACA;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,mBAAmB,aAAa;AAAA,UAChC,aAAa,OAAO;AAAA,UACpB,mBAAmB,OAAO;AAAA,UAC1B,qBAAqB,OAAO;AAAA,UAC5B,iBAAiB,OAAO;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,qBAAqB;AAAA,MACjC,UAAU,cAAc;AAAA,MACxB,mBAAmB,aAAa;AAAA,MAChC,aAAa,OAAO;AAAA,MACpB,mBAAmB,OAAO;AAAA,MAC1B,iBAAiB,aAAa;AAAA,MAC9B,qBAAqB,OAAO;AAAA,MAC5B,iBAAiB,OAAO;AAAA,MACxB,MAAM;AAAA,IACR,CAAC;AAED,UAAM,yBAAyB,MAAM,KAAK,YAAY,SAAS,KAAK,MAAM,GAAG;AAAA,MAC3E;AAAA,MACA,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,oBAAoBA,MAAK,QAAQ,sBAAsB,EAAE,mBAAmB;AAElF,WAAO;AAAA,MACL,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,oCACJ,eACA,cACA,sBACA,WACA,qBACA,6BAI4B;AAE5B,UAAM,SAAS,yBAAyB,sBAAsB,KAAK,aAAa;AAEhF,UAAM,EAAE,aAAa,mBAAmB,IAAI,IAAI,MAAM,KAAK;AAAA,MACzD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAIA,QAAI,kBAAkB,MAAM,MAAM,oBAAoB,MAAM,GAAG;AAC7D,YAAM,IAAI,MAAM,6DAA6D;AAAA,IAC/E;AAIA,UAAM,kBAAkB,OAAO,mBAAmB,IAAI,CAAC,aAAa,OAAO,KAAK,UAAU,KAAK,CAAC;AAChG,UAAM,UAAU;AAAA;AAAA;AAAA;AAAA,MAId,kBAAkB,IAAI,CAAC,EAAE;AAAA,MACzB;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAEA,sBAAkB,IAAI,CAAC,EAAE,UAAU;AAEnC,WAAO;AAAA,MACL,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,gDACJ,eACA,cACA,sBACA,kBACA,SAC4B;AAC5B,UAAM,SAAS,yBAAyB,sBAAsB,KAAK,aAAa;AAEhF,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,MAAME,gBAAe,IAAI,IAAI,QAAQ,uCAAuC,kBAAkB,OAAO;AAE7G,UAAM,YAAwB;AAAA,MAC5B;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,gBAAgB,OAAO;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,uBAAuB;AAAA,MACnC,UAAU,cAAc;AAAA,MACxB,gBAAgB,OAAO;AAAA,MACvB,MAAM;AAAA,IACR,CAAC;AAED,UAAM,0BAA0B,MAAM,KAAK,YAAY,SAASA,eAAc,MAAM,GAAG;AAAA,MACrF;AAAA,MACA,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,aAAaF,MAAK,QAAQ,uBAAuB,EAAE,mBAAmB;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,iDACJ,eACA,cACA,sBACA,WACA,SAC4B;AAC5B,UAAM,SAAS,yBAAyB,sBAAsB,KAAK,aAAa;AAEhF,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,MAAM,IAAI,IAAI,QAAQ,iCAAiC,WAAW,OAAO;AAEjF,UAAM,YAAwB;AAAA,MAC5B;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,gBAAgB,aAAa;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,uBAAuB;AAAA,MACnC,UAAU,cAAc;AAAA,MACxB,gBAAgB,aAAa;AAAA,MAC7B,MAAM;AAAA,IACR,CAAC;AAED,UAAM,0BAA0B,MAAM,KAAK,YAAY,SAAS,KAAK,MAAM,GAAG;AAAA,MAC5E;AAAA,MACA,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,aAAaA,MAAK,QAAQ,uBAAuB,EAAE,mBAAmB;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,2CACJ,eACA,cACA,sBACA,YACA,SAC4B;AAC5B,UAAM,SAAS,yBAAyB,sBAAsB,KAAK,aAAa;AAEhF,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,MAAM,IAAI,IAAI,QAAQ,2BAA2B,YAAY,OAAO;AAE5E,UAAM,YAAwB;AAAA,MAC5B;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,gBAAgB,OAAO;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,uBAAuB;AAAA,MACnC,UAAU,cAAc;AAAA,MACxB,gBAAgB,OAAO;AAAA,MACvB,MAAM;AAAA,IACR,CAAC;AAED,UAAM,+BAA+B,MAAM,KAAK,YAAY,SAAS,KAAK,MAAM,GAAG;AAAA,MACjF;AAAA,MACA,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,aAAaA,MAAK,QAAQ,4BAA4B,EAAE,mBAAmB;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,wBACJ,SACA,eACA,kBAC+B;AAC/B,QAAI,UAAsB,WAAW;AAKrC,QAAI,UAAU,kBAAkB,KAAK,OAAO,KAAK,eAAe,kBAAkB,KAAK,OAAO,GAAG;AAC/F,gBAAU,WAAW;AAAA,IACvB;AAEA,UAAM,CAAC,SAAS,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,MACjD,KAAK,gBAAgB,aAAa;AAAA,MAClC,KAAK,gBAAgB,mBAAmB;AAAA,IAC1C,CAAC;AAED,UAAM,gBAAgB,KAAK,eAAe;AAG1C,UAAM,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,QACf,eAAe,cAAc;AAAA,QAC7B,SAAS,cAAc;AAAA,MACzB;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,SAAS;AAAA,MACrB;AAAA,MACA,MAAM;AAAA,IACR,CAAC;AAED,UAAM,uBAAuB,MAAM,KAAK,YAAY;AAAA,MAClD;AAAA,MACA,YAAY,WAAW,SAAS,kBAAkB;AAAA,IACpD;AAEA,QAAI;AACJ,QAAI,YAAY,WAAW,QAAQ;AACjC,YAAM,YAAY,UAAU,YAAY;AAAA,QACtC,SAAS;AAAA,QACT,KAAK,OAAO,KAAK,sBAAsB,QAAQ;AAAA,MACjD,CAAC;AAED,eAAS,UAAU,OAAO,SAAS,EAAE,OAAO;AAAA,IAC9C,OAAO;AAEL,eAAS,OAAO,KAAK,sBAAsB,QAAQ;AAAA,IACrD;AAEA,WAAO;AAAA,MACL,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAc,qCAAqC,iBAA0B,WAAwB;AACnG,UAAM,EAAE,aAAa,YAAY,IAAI,gBAAgB,2BAA2B,SAAS;AAGzF,UAAM,EAAE,MAAM,aAAa,IAAI,gBAAgB,gCAAgC,SAAS;AAExF,UAAM,EAAE,MAAM,sBAAsB,IAAI,gBAAgB,kCAAkC,WAAW;AAErG,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAa,uBACX,SACA,iBACA,cACA,WACA,eACA,eACA,QACA,SAUC;AACD,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,UAAM,EAAE,aAAa,cAAc,sBAAsB,IAAI,MAAM,KAAK;AAAA,MACtE;AAAA,MACA;AAAA,IACF;AAEA,UAAM,oBAAgC;AAAA,MACpC;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,mBAAmB,aAAa;AAAA,UAChC,aAAa,OAAO;AAAA,UACpB,mBAAmB,OAAO;AAAA,UAC1B,kBAAkB,OAAO;AAAA,UACzB,iBAAiB,aAAa;AAAA,QAChC;AAAA,MACF;AAAA,MACA;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,qBAAqB,OAAO;AAAA,UAC5B,gBAAgB,OAAO,SAAS;AAAA,QAClC;AAAA,MACF;AAAA,MACA;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,qBAAqB,OAAO,SAAS;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAGA,SAAK,IAAI,KAAK,SAAS;AAAA,MACrB,UAAU,cAAc;AAAA,MACxB,mBAAmB,aAAa;AAAA,MAChC,aAAa,OAAO;AAAA,MACpB,mBAAmB,OAAO;AAAA,MAC1B,qBAAqB,OAAO;AAAA,MAC5B,iBAAiB,aAAa;AAAA,MAC9B,gBAAgB,OAAO,SAAS;AAAA,MAChC,qBAAqB,OAAO,SAAS;AAAA,MACrC,MAAM;AAAA,IACR,CAAC;AAED,UAAM,wBAAwB,MAAM,KAAK,YAAY,SAAS,aAAa,MAAM,GAAG;AAAA,MAClF,WAAW;AAAA,MACX,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,mBAAmBA,MAAK,QAAQ,qBAAqB,EAAE,mBAAmB;AAChF,UAAM,cAAc,4CAA4C,gBAAgB;AAChF,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC1E;AAEA,UAAM,6BAAyC;AAAA,MAC7C;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,mBAAmB,aAAa;AAAA,UAChC,aAAa,OAAO;AAAA,UACpB,mBAAmB,OAAO;AAAA,UAC1B,qBAAqB,OAAO;AAAA,UAC5B,iBAAiB,OAAO;AAAA,QAC1B;AAAA,MACF;AAAA,MACA;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,qBAAqB,OAAO;AAAA,UAC5B,gBAAgB,OAAO,SAAS;AAAA,QAClC;AAAA,MACF;AAAA,MACA;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,qBAAqB,OAAO,SAAS;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAGA,SAAK,IAAI,KAAK,SAAS;AAAA,MACrB,UAAU,cAAc;AAAA,MACxB,mBAAmB,aAAa;AAAA,MAChC,aAAa,OAAO;AAAA,MACpB,mBAAmB,OAAO;AAAA,MAC1B,qBAAqB,OAAO;AAAA,MAC5B,iBAAiB,OAAO;AAAA,MACxB,gBAAgB,OAAO,SAAS;AAAA,MAChC,qBAAqB,OAAO,SAAS;AAAA,MACrC,MAAM;AAAA,IACR,CAAC;AAED,UAAM,iCAAiC,MAAM,KAAK,YAAY,SAAS,sBAAsB,MAAM,GAAG;AAAA,MACpG,WAAW;AAAA,MACX,QAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,4BAA4BA,MAAK,QAAQ,8BAA8B,EAAE,mBAAmB;AAClG,UAAM,sBAAsB,4CAA4C,yBAAyB;AACjG,QAAI,CAAC,qBAAqB;AACxB,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AAGA,UAAM,oBAAoB,MAAM,KAAK,wBAAwB,SAAS,eAAe,cAAc,OAAO;AAE1G,UAAM,YAAY;AAAA,MAChB,YAAY;AAAA,MACZ,KAAK;AAAA,MACL,OAAO,WAAW,KAAK,OAAO,KAAK,cAAc,qBAAqB,KAAK,CAAC;AAAA,MAC5E,aAAa,aAAa,8BAA8B,IAAI,CAAC,OAAO,WAAW,KAAK,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC;AAAA,MAC3G,aAAa,aAAa;AAAA,MAC1B,cAAc,aAAa;AAAA,MAC3B,WAAW,WAAW,KAAK,UAAU,SAAS,CAAC;AAAA,MAC/C,YAAY,WAAW,KAAK,OAAO,KAAK,kBAAkB,gBAAgB,EAAE,MAAM,GAAG,KAAK,CAAC;AAAA,MAC3F,sBAAsB,WAAW,KAAK,WAAW;AAAA,MACjD,eAAe,OAAO;AAAA,MACtB,aAAa,WAAW,KAAK,YAAY,SAAS,CAAC;AAAA,MACnD,gBAAgB,aAAa,mBAAmB,OAAO;AAAA,MACvD,qBAAqB,WAAW,KAAK,OAAO,KAAK,kBAAkB,yBAAyB,EAAE,MAAM,GAAG,KAAK,CAAC;AAAA,MAC7G,+BAA+B,WAAW,KAAK,mBAAmB;AAAA,IACpE;AAGA,QAAI,SAAS,yBAAyB;AACpC,YAAM,YAAY,WAAW,KAAK,QAAQ,wBAAwB,UAAU,SAAS,CAAC;AACtF,YAAMG,OAAM,aAAa,kBAAkB,YAAY;AAAA,QACrD,GAAG;AAAA,QACH,uBAAuB,QAAQ,wBAAwB,kBAAkB,MAAM;AAAA,QAC/E;AAAA,MACF,CAAC;AACD,aAAO;AAAA,QACL,SAAS,2BAA2B;AAAA,QACpC,OAAOA;AAAA,MACT;AAAA,IACF;AAGA,UAAM,MAA2C,aAAa,uBAAuB,YAAY;AAAA,MAC/F,GAAG;AAAA,MACH,yBAAyB,SAAS;AAAA,IACpC,CAAC;AAED,WAAO;AAAA,MACL,SAAS,2BAA2B;AAAA,MACpC,OAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,kBAAkB,gBAA2D;AACnF,UAAM,EAAE,KAAK,QAAQ,aAAa,IAAI;AACtC,UAAM,WAAW,kBAAkB,MAAM;AAEzC,UAAM,OAAO,cAAc,WAAW,KAAK,OAAO,KAAK,cAAc,KAAK,CAAC,CAAC;AAC5E,UAAM,oBAAkD,cAAc,eAAe,YAAY;AAAA,MAC/F,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AACD,WAAO,WAAW,eAAe,YAAY;AAAA,MAC3C,KAAK;AAAA,MACL,OAAO,WAAW,KAAK,OAAO,KAAK,UAAU,KAAK,CAAC;AAAA,IACrD,CAAC;AAAA,EACH;AACF;AAQO,IAAM,gCAAgC,CAAC,gBAAqC;AACjF,MAAI;AAEF,WAAO,YAAY,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK;AAAA,EACrD,SAAS,OAAO;AACd,UAAM,aAAa,YAAY,4CAAuC,gCAAgC;AAAA,EACxG;AACF;;;AMxvCA,SAAS,WAAAC,UAAS,UAAAC,eAAc;AAYzB,IAAM,8BAAN,cAA0C,kBAAkB;AAAA,EAIjE,YACE,WACA,sBACA,cACA,mBACA,iBACA,mBACA,YACA;AACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QACE,CAAC,YACD;AACA,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAEA,QAAI,WAAW,UAAU,iBAAiB;AACxC,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,uBAA+B;AAE7B,QAAI,KAAK,qBAAqB,UAAU,GAAG;AACzC,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACpE;AAEA,UAAM,UAAU,OAAO,MAAM,CAAC;AAC9B,YAAQ,WAAW,CAAC;AAEpB,UAAM,kBAAkB,OAAO,MAAM,CAAC;AAEtC,oBAAgB,cAAc,KAAK,eAAe;AAClD,UAAM,wBAAwB,OAAO,OAAO;AAAA,MAC1C,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL,KAAK,qBAAqB,CAAC;AAAA,MAC3B;AAAA,IACF,CAAC;AACD,WAAOC,QAAO,QAAQ,CAACC,SAAQ,WAAW,qBAAqB,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAyC;AACvC,UAAM,UAAU,MAAM,aAAa;AACnC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,iBAAiB,KAAK,qBAAqB;AAAA,IAC7C;AAAA,EACF;AACF;;;ACpEO,IAAM,oBAAN,cAAgC,QAAQ;AAAA,EAE7C,YACE,SACA,YACA,QACA,+BACA,iBACA;AACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,OAAO,KAAK;AACf,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,OAAO,qBAAqB;AAC/B,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAGA,QAAI,8BAA8B,WAAW,GAAG;AAC9C,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,eAAyC;AACvC,UAAM,EAAE,gBAAgB,oBAAoB,eAAe,IAAI,IAAI,KAAK;AAExE,QAAI;AACJ,QAAI;AACF,0BAAoB,IAAI;AAAA,QACtB,OAAO,KAAK,KAAK,WAAW,qBAAqB,KAAK;AAAA,QACtD,KAAK,8BAA8B,IAAI,CAAC,OAAO,OAAO,KAAK,IAAI,KAAK,CAAC;AAAA,QACrE,UAAU,kBAAkB;AAAA,QAC5B;AAAA,QACA,KAAK;AAAA,QACL;AAAA,QACA,OAAO,KAAK,KAAK,KAAK;AAAA,MACxB;AAAA,IACF,SAAS,OAAgB;AACvB,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,gBAAU,kBAAkB,aAAa;AAAA,IAC3C,SAAS,OAAgB;AACvB,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBO,yBACL,kBACA,YACA,SACmB;AACnB;AAAA,MACE;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,aAAa;AAGlC,QAAI;AACF,YAAM,EAAE,aAAa,IAAI,IAAI;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,KAAK,WAAW;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,QACL;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA,KAAK,OAAO,sBAAsB;AAAA,MACpC;AAEA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAgB;AACvB,YAAM,aAAa;AAAA,QACjB;AAAA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,cACL,WACA,YACM;AACN,WAAO;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL;AAAA,MACA;AAAA,QACE,KAAK,WAAW;AAAA,QAAS,KAAK;AAAA,MAChC,IAAI,OAAO,KAAK,KAAK,WAAW,qBAAqB,KAAK,IAAI;AAAA,IAChE;AAAA,EACF;AACF;;;ACzJO,SAAS,YAAY,QAAuG;AACjI,SAAO,OAAO,aAAa;AAC7B;",
6
+ "names": ["address", "address", "payments", "payments", "BitcoinScriptType", "script", "payments", "Psbt", "Transaction", "payments", "script", "address", "opcodes", "bitcoinScript", "opcodes", "payments", "script", "opcodes", "payments", "script", "bitcoinScript", "Transaction", "address", "script", "payments", "Psbt", "stakingTransaction", "opcodes", "address", "Psbt", "Transaction", "Transaction", "stakingPsbt", "Psbt", "stakingExpansionPsbt", "unbondingPsbt", "msg", "opcodes", "script", "script", "opcodes"]
7
+ }