@bitgo-beta/babylonlabs-io-btc-staking-ts 0.4.0-beta.51 → 0.4.0-beta.511
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +1353 -1099
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.cts +339 -269
- package/dist/index.js +1322 -1068
- package/dist/index.js.map +7 -0
- package/package.json +5 -4
|
@@ -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/constants/unbonding.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/staking/index.ts", "../src/staking/manager.ts", "../src/constants/registry.ts", "../src/utils/index.ts", "../src/utils/babylon.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 { MIN_UNBONDING_OUTPUT_VALUE } from \"../../constants/unbonding\";\nimport { StakingError, StakingErrorCode } from \"../../error\";\nimport { StakingParams } from \"../../types/params\";\nimport { TransactionOutput } from \"../../types/psbtOutputs\";\nimport { UTXO } from \"../../types/UTXO\";\nimport { isValidNoCoordPublicKey } from \"../btc\";\n\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 * 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 * 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", "// 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", "// minimum unbonding output value to avoid the unbonding output value being\n// less than Bitcoin dust\nexport const MIN_UNBONDING_OUTPUT_VALUE = 1000;", "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\";\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\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 { Psbt, Transaction, networks, payments, script, address, opcodes } 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 { getStakingTxInputUTXOsAndFees, getWithdrawTxFee } from \"../utils/fee\";\nimport { inputValueSum } from \"../utils/fee/utils\";\nimport { buildStakingTransactionOutputs, deriveUnbondingOutputInfo } 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 * 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 // Verify all btcPkHex from covenantSigs exist in paramsCovenants\n for (const sig of covenantSigs) {\n const btcPkHexBuf = Buffer.from(sig.btcPkHex, \"hex\");\n if (!paramsCovenants.some(covenant => covenant.equals(btcPkHexBuf))) {\n throw new Error(\n `Covenant signature public key ${sig.btcPkHex} not found in params covenants`\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 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/**\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\nexport const P2TR_INPUT_SIZE = 58;\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;", "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 validateParams,\n validateStakingTimelock,\n validateStakingTxInputData,\n} from \"../utils/staking\";\nimport { stakingPsbt, unbondingPsbt } from \"./psbt\";\nimport { StakingScriptData, StakingScripts } from \"./stakingScript\";\nimport {\n slashEarlyUnbondedTransaction,\n slashTimelockUnbondedTransaction,\n stakingTransaction,\n unbondingTransaction,\n withdrawEarlyUnbondedTransaction,\n withdrawSlashingTransaction,\n withdrawTimelockUnbondedTransaction,\n} from \"./transactions\";\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 * 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 * 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 {\n btccheckpoint,\n btcstaking,\n btcstakingtx,\n} 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 {\n BabylonProvider,\n BtcProvider,\n InclusionProof,\n StakingInputs,\n} 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 {\n deriveStakingOutputInfo,\n findMatchingTxOutputIndex,\n} from \"../utils/staking\";\nimport {\n getBabylonParamByBtcHeight,\n getBabylonParamByVersion,\n} from \"../utils/staking/param\";\nimport { createCovenantWitness } from \"./transactions\";\n\nexport class BabylonBtcStakingManager {\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 ) {\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\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(\n babylonBtcTipHeight,\n this.stakingParams,\n );\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(\n stakingInput.stakingAmountSat,\n inputUTXOs,\n feeRate,\n );\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 * 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(\n stakingTxHeight,\n this.stakingParams,\n );\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(\n stakingTx,\n stakingOutputInfo.outputAddress,\n this.network,\n );\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 this.getInclusionProof(inclusionProof),\n );\n\n this.ee?.emit(\"delegation:register\", {\n type: \"create-btc-delegation-msg\",\n });\n\n return {\n signedBabylonTx:\n 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(\n babylonBtcTipHeight,\n this.stakingParams,\n );\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(\n stakingInput.stakingAmountSat,\n inputUTXOs,\n feeRate,\n );\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(\n stakingParamsVersion,\n this.stakingParams,\n );\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(\n stakingPsbt.toHex(),\n {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_STAKING_TRANSACTION,\n },\n },\n );\n\n return Psbt.fromHex(signedStakingPsbtHex).extractTransaction();\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(\n stakingParamsVersion,\n this.stakingParams,\n );\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 } =\n 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(\n psbt.toHex(),\n {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_UNBONDING_TRANSACTION,\n },\n },\n );\n\n const signedUnbondingTx = Psbt.fromHex(\n signedUnbondingPsbtHex,\n ).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(\n stakingParamsVersion,\n this.stakingParams,\n );\n\n const { transaction: signedUnbondingTx, fee } =\n 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(\n \"Unbonding transaction hash does not match the computed hash\",\n );\n }\n\n // Add covenant unbonding signatures\n // Convert the params of covenants to buffer\n const covenantBuffers = params.covenantNoCoordPks.map((covenant) =>\n Buffer.from(covenant, \"hex\"),\n );\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(\n stakingParamsVersion,\n this.stakingParams,\n );\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 } =\n 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(\n unbondingPsbt.toHex(),\n {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_WITHDRAW_TRANSACTION,\n },\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(\n stakingParamsVersion,\n this.stakingParams,\n );\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(\n stakingTx,\n feeRate,\n );\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(\n psbt.toHex(),\n {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_WITHDRAW_TRANSACTION,\n },\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(\n stakingParamsVersion,\n this.stakingParams,\n );\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(\n slashingTx,\n feeRate,\n );\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(\n psbt.toHex(),\n {\n contracts,\n action: {\n name: ActionName.SIGN_BTC_WITHDRAW_TRANSACTION,\n },\n },\n );\n\n return {\n transaction: Psbt.fromHex(\n signedWithrawSlashingPsbtHex,\n ).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\",\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 (\n isTaproot(stakerBtcAddress, this.network) ||\n isNativeSegwit(stakerBtcAddress, this.network)\n ) {\n sigType = BTCSigType.BIP322;\n }\n\n this.ee?.emit(channel, {\n bech32Address,\n type: \"proof-of-possession\",\n });\n\n const signedBabylonAddress = await this.btcProvider.signMessage(\n bech32Address,\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(\n stakingInstance: Staking,\n stakingTx: Transaction,\n ) {\n const { transaction: unbondingTx } =\n stakingInstance.createUnbondingTransaction(stakingTx);\n\n // Create slashing transactions and extract signatures\n const { psbt: slashingPsbt } =\n stakingInstance.createStakingOutputSlashingPsbt(stakingTx);\n\n const { psbt: unbondingSlashingPsbt } =\n 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 inclusionProof - The inclusion proof of the staking transaction.\n * @returns The protobuf message.\n */\n public async createBtcDelegationMsg(\n channel: \"delegation:create\" | \"delegation:register\",\n stakingInstance: Staking,\n stakingInput: StakingInputs,\n stakingTx: Transaction,\n bech32Address: string,\n stakerBtcInfo: StakerInfo,\n params: StakingParams,\n inclusionProof?: btcstaking.InclusionProof,\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 } =\n 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(\n slashingPsbt.toHex(),\n {\n contracts: slashingContracts,\n action: {\n name: ActionName.SIGN_BTC_SLASHING_TRANSACTION,\n },\n },\n );\n\n const signedSlashingTx = Psbt.fromHex(\n signedSlashingPsbtHex,\n ).extractTransaction();\n const slashingSig =\n 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(\n unbondingSlashingPsbt.toHex(),\n {\n contracts: unbondingSlashingContracts,\n action: {\n name: ActionName.SIGN_BTC_UNBONDING_SLASHING_TRANSACTION,\n },\n },\n );\n\n const signedUnbondingSlashingTx = Psbt.fromHex(\n signedUnbondingSlashingPsbtHex,\n ).extractTransaction();\n const unbondingSignatures = extractFirstSchnorrSignatureFromTransaction(\n signedUnbondingSlashingTx,\n );\n if (!unbondingSignatures) {\n throw new Error(\n \"No signature found in the unbonding output slashing PSBT\",\n );\n }\n\n // Create proof of possession\n const proofOfPossession = await this.createProofOfPossession(\n channel,\n bech32Address,\n stakerBtcInfo.address,\n );\n\n // Prepare the final protobuf message\n const msg: btcstakingtx.MsgCreateBTCDelegation =\n btcstakingtx.MsgCreateBTCDelegation.fromPartial({\n stakerAddr: bech32Address,\n pop: proofOfPossession,\n btcPk: Uint8Array.from(\n Buffer.from(stakerBtcInfo.publicKeyNoCoordHex, \"hex\"),\n ),\n fpBtcPkList: stakingInput.finalityProviderPksNoCoordHex.map((pk) =>\n Uint8Array.from(Buffer.from(pk, \"hex\")),\n ),\n stakingTime: stakingInput.stakingTimelock,\n stakingValue: stakingInput.stakingAmountSat,\n stakingTx: Uint8Array.from(stakingTx.toBuffer()),\n slashingTx: Uint8Array.from(\n Buffer.from(clearTxSignatures(signedSlashingTx).toHex(), \"hex\"),\n ),\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(\n Buffer.from(\n clearTxSignatures(signedUnbondingSlashingTx).toHex(),\n \"hex\",\n ),\n ),\n delegatorUnbondingSlashingSig: Uint8Array.from(unbondingSignatures),\n stakingTxInclusionProof: 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(\n inclusionProof: InclusionProof,\n ): btcstaking.InclusionProof {\n const { pos, merkle, blockHashHex } = inclusionProof;\n const proofHex = deriveMerkleProof(merkle);\n\n const hash = reverseBuffer(\n Uint8Array.from(Buffer.from(blockHashHex, \"hex\")),\n );\n const inclusionProofKey: btccheckpoint.TransactionKey =\n 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 * 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 */\nconst 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\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 */\nconst 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 */\nconst 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 * 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 = (\n unbondingTx: Transaction,\n): 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(\n error,\n StakingErrorCode.INVALID_INPUT,\n \"Failed to get staker signature\",\n );\n }\n};\n", "export const BABYLON_REGISTRY_TYPE_URLS = {\n MsgCreateBTCDelegation: \"/babylon.btcstaking.v1.MsgCreateBTCDelegation\",\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 { 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 { 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, validateStakingTxInputData } from \"../../utils/staking\";\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;;;ACD7D,IAAM,6BAA6B;;;AFuBnC,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;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;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;;;AGxYA,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;;;AJtDO,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;AAAW,SAAK,WAAW,UAAU,OAAO;AACtE,MAAI,UAAU,aAAa;AAAW,SAAK,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,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,OAAOC,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;;;AK9JA,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,SAAS,QAAAC,OAAM,eAAAC,cAAuB,YAAAC,WAAU,UAAAC,SAAQ,WAAAC,UAAS,WAAAC,gBAAe;;;ACAzE,IAAM,eAAe;;;ACA5B,SAAS,UAAUC,sBAAqB;;;ACCjC,IAAM,qBAAqB;AAE3B,IAAM,oBAAoB;AAE1B,IAAM,kBAAkB;AAExB,IAAM,0BAA0B;AAEhC,IAAM,sCAAsC;AAE5C,IAAM,6BAA6B;AAEnC,IAAM,0BAA0B;AAEhC,IAAM,kCAAkC;AAExC,IAAM,8BAA8B;AAGpC,IAAM,iCAAiC;;;ACpB9C,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;;;AF5BO,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;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;;;AGlLO,IAAM,mBAAmB;AAEzB,IAAM,sBAAsB;;;ALWnC,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;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,aAAW,OAAO,cAAc;AAC9B,UAAM,cAAc,OAAO,KAAK,IAAI,UAAU,KAAK;AACnD,QAAI,CAAC,gBAAgB,KAAK,cAAY,SAAS,OAAO,WAAW,CAAC,GAAG;AACnE,YAAM,IAAI;AAAA,QACR,iCAAiC,IAAI,QAAQ;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAKA,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;;;AM/rBO,IAAM,UAAN,MAAc;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,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,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;;;AC/dA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,QAAAO,aAAmC;;;ACVrC,IAAM,6BAA6B;AAAA,EACxC,wBAAwB;AAC1B;;;ACGO,IAAM,gBAAgB,CAAC,WAAmC;AAC/D,QAAM,eAAe,IAAI,WAAW,MAAM;AAC1C,MAAI,aAAa,SAAS;AAAG,WAAO;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,kBAAkB;AAQpB,IAAM,wBAAwB,CAACC,aAA6B;AACjE,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,WAAWA,QAAO;AACrC,WAAO,WAAW;AAAA,EACpB,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;;;ACPO,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;AAAQ,UAAM,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;AAAQ,UAAM,IAAI,MAAM,wCAAwC,OAAO,EAAE;AAC9E,SAAO;AACT;;;AJEO,IAAM,2BAAN,MAA+B;AAAA,EACpC,YACY,SACA,eACA,aACA,iBACA,IACV;AALU;AACA;AACA;AACA;AACA;AAEV,SAAK,UAAU;AAEf,QAAI,cAAc,WAAW,GAAG;AAC9B,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAGA,UAAM,EAAE,YAAY,IAAI,QAAQ;AAAA,MAC9B,aAAa;AAAA,MACb;AAAA,MACA;AAAA,IACF;AAGA,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,wCACJ,eACA,WACA,iBACA,cACA,gBACA,gBAGC;AAED,UAAM,SAAS;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,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;AAAA,MACE;AAAA,MACA,kBAAkB;AAAA,MAClB,KAAK;AAAA,IACP;AAGA,UAAM,gBAAgB,MAAM,KAAK;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,kBAAkB,cAAc;AAAA,IACvC;AAEA,SAAK,IAAI,KAAK,uBAAuB;AAAA,MACnC,MAAM;AAAA,IACR,CAAC;AAED,WAAO;AAAA,MACL,iBACE,MAAM,KAAK,gBAAgB,gBAAgB,aAAa;AAAA,IAC5D;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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,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;AAAA,MAClC,aAAa;AAAA,MACb;AAAA,MACA;AAAA,IACF;AAEA,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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,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;AAAA,MAClDA,aAAY,MAAM;AAAA,MAClB;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAOC,MAAK,QAAQ,oBAAoB,EAAE,mBAAmB;AAAA,EAC/D;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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,aAAa,aAAa,IAAI,IACpC,QAAQ,2BAA2B,SAAS;AAE9C,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;AAAA,MACpD,KAAK,MAAM;AAAA,MACX;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,oBAAoBA,MAAK;AAAA,MAC7B;AAAA,IACF,EAAE,mBAAmB;AAErB,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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,UAAM,EAAE,aAAa,mBAAmB,IAAI,IAC1C,MAAM,KAAK;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAIF,QAAI,kBAAkB,MAAM,MAAM,oBAAoB,MAAM,GAAG;AAC7D,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAIA,UAAM,kBAAkB,OAAO,mBAAmB;AAAA,MAAI,CAAC,aACrD,OAAO,KAAK,UAAU,KAAK;AAAA,IAC7B;AACA,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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,UAAM,UAAU,IAAI;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,UAAM,EAAE,MAAMC,gBAAe,IAAI,IAC/B,QAAQ,uCAAuC,kBAAkB,OAAO;AAE1E,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;AAAA,MACrDA,eAAc,MAAM;AAAA,MACpB;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,aAAaD,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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,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;AAAA,MAC5B;AAAA,MACA;AAAA,IACF;AAEA,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;AAAA,MACrD,KAAK,MAAM;AAAA,MACX;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,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;AAAA,MACb;AAAA,MACA,KAAK;AAAA,IACP;AAEA,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;AAAA,MAC5B;AAAA,MACA;AAAA,IACF;AAEA,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;AAAA,MAC1D,KAAK,MAAM;AAAA,MACX;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,aAAaA,MAAK;AAAA,QAChB;AAAA,MACF,EAAE,mBAAmB;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,wBACJ,SACA,eACA,kBAC+B;AAC/B,QAAI,UAAsB,WAAW;AAKrC,QACE,UAAU,kBAAkB,KAAK,OAAO,KACxC,eAAe,kBAAkB,KAAK,OAAO,GAC7C;AACA,gBAAU,WAAW;AAAA,IACvB;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,qCACZ,iBACA,WACA;AACA,UAAM,EAAE,aAAa,YAAY,IAC/B,gBAAgB,2BAA2B,SAAS;AAGtD,UAAM,EAAE,MAAM,aAAa,IACzB,gBAAgB,gCAAgC,SAAS;AAE3D,UAAM,EAAE,MAAM,sBAAsB,IAClC,gBAAgB,kCAAkC,WAAW;AAE/D,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,EAeA,MAAa,uBACX,SACA,iBACA,cACA,WACA,eACA,eACA,QACA,gBACA;AACA,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI;AAAA;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,UAAM,EAAE,aAAa,cAAc,sBAAsB,IACvD,MAAM,KAAK;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAEF,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;AAAA,MACnD,aAAa,MAAM;AAAA,MACnB;AAAA,QACE,WAAW;AAAA,QACX,QAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,mBAAmBA,MAAK;AAAA,MAC5B;AAAA,IACF,EAAE,mBAAmB;AACrB,UAAM,cACJ,4CAA4C,gBAAgB;AAC9D,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;AAAA,MAC5D,sBAAsB,MAAM;AAAA,MAC5B;AAAA,QACE,WAAW;AAAA,QACX,QAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,4BAA4BA,MAAK;AAAA,MACrC;AAAA,IACF,EAAE,mBAAmB;AACrB,UAAM,sBAAsB;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,CAAC,qBAAqB;AACxB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,UAAM,oBAAoB,MAAM,KAAK;AAAA,MACnC;AAAA,MACA;AAAA,MACA,cAAc;AAAA,IAChB;AAGA,UAAM,MACJ,aAAa,uBAAuB,YAAY;AAAA,MAC9C,YAAY;AAAA,MACZ,KAAK;AAAA,MACL,OAAO,WAAW;AAAA,QAChB,OAAO,KAAK,cAAc,qBAAqB,KAAK;AAAA,MACtD;AAAA,MACA,aAAa,aAAa,8BAA8B;AAAA,QAAI,CAAC,OAC3D,WAAW,KAAK,OAAO,KAAK,IAAI,KAAK,CAAC;AAAA,MACxC;AAAA,MACA,aAAa,aAAa;AAAA,MAC1B,cAAc,aAAa;AAAA,MAC3B,WAAW,WAAW,KAAK,UAAU,SAAS,CAAC;AAAA,MAC/C,YAAY,WAAW;AAAA,QACrB,OAAO,KAAK,kBAAkB,gBAAgB,EAAE,MAAM,GAAG,KAAK;AAAA,MAChE;AAAA,MACA,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;AAAA,QAC9B,OAAO;AAAA,UACL,kBAAkB,yBAAyB,EAAE,MAAM;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAAA,MACA,+BAA+B,WAAW,KAAK,mBAAmB;AAAA,MAClE,yBAAyB;AAAA,IAC3B,CAAC;AAEH,WAAO;AAAA,MACL,SAAS,2BAA2B;AAAA,MACpC,OAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,kBACN,gBAC2B;AAC3B,UAAM,EAAE,KAAK,QAAQ,aAAa,IAAI;AACtC,UAAM,WAAW,kBAAkB,MAAM;AAEzC,UAAM,OAAO;AAAA,MACX,WAAW,KAAK,OAAO,KAAK,cAAc,KAAK,CAAC;AAAA,IAClD;AACA,UAAM,oBACJ,cAAc,eAAe,YAAY;AAAA,MACvC,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AACH,WAAO,WAAW,eAAe,YAAY;AAAA,MAC3C,KAAK;AAAA,MACL,OAAO,WAAW,KAAK,OAAO,KAAK,UAAU,KAAK,CAAC;AAAA,IACrD,CAAC;AAAA,EACH;AACF;AAaA,IAAM,8CAA8C,CAClD,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;AAUA,IAAM,oBAAoB,CAAC,OAAiC;AAC1D,KAAG,IAAI,QAAQ,CAAC,UAAU;AACxB,UAAM,SAAS,OAAO,MAAM,CAAC;AAC7B,UAAM,UAAU,CAAC;AAAA,EACnB,CAAC;AACD,SAAO;AACT;AAQA,IAAM,oBAAoB,CAAC,WAAqB;AAC9C,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;AAQO,IAAM,gCAAgC,CAC3C,gBACW;AACX,MAAI;AAEF,WAAO,YAAY,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK;AAAA,EACrD,SAAS,OAAO;AACd,UAAM,aAAa;AAAA,MACjB;AAAA;AAAA,MAEA;AAAA,IACF;AAAA,EACF;AACF;;;AK3kCA,SAAS,WAAAE,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;;;ACrEO,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;;;ACxJO,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", "Psbt", "address", "stakingPsbt", "Psbt", "unbondingPsbt", "opcodes", "script", "script", "opcodes"]
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitgo-beta/babylonlabs-io-btc-staking-ts",
|
|
3
|
-
"version": "0.4.0-beta.
|
|
3
|
+
"version": "0.4.0-beta.511",
|
|
4
4
|
"description": "Library exposing methods for the creation and consumption of Bitcoin transactions pertaining to Babylon's Bitcoin Staking protocol.",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -27,13 +27,14 @@
|
|
|
27
27
|
"btc-staking"
|
|
28
28
|
],
|
|
29
29
|
"engines": {
|
|
30
|
-
"node": ">=
|
|
30
|
+
"node": ">=20 < 23"
|
|
31
31
|
},
|
|
32
32
|
"author": "Babylon Labs Ltd.",
|
|
33
33
|
"license": "SEE LICENSE IN LICENSE",
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"dts-bundle-generator": "^9.3.1",
|
|
36
|
-
"esbuild": "^0.20.2"
|
|
36
|
+
"esbuild": "^0.20.2",
|
|
37
|
+
"nanoevents": "^9.1.0"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
40
|
"@babylonlabs-io/babylon-proto-ts": "1.0.0",
|
|
@@ -45,5 +46,5 @@
|
|
|
45
46
|
"publishConfig": {
|
|
46
47
|
"access": "public"
|
|
47
48
|
},
|
|
48
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "6333f6d3f27c6801bce9ebc73c47593a1f3b88a1"
|
|
49
50
|
}
|