import { SmartContract } from '../smartContract.js'; import { FixedArray, TxOut } from '../types/index.js'; import { ContractCall } from '../../psbt/types.js'; /** * Maximum number of inputs allowed during genesis deployment. * * ## Purpose * Limits the number of inputs validated to prevent script size bloat while * maintaining sufficient security coverage. * * ## Why 6? * - **Typical deployments**: 1-3 inputs (Genesis UTXO + fee UTXOs) * - **Edge case coverage**: Handles multi-input deployment scenarios * - **Script size**: Each input check adds ~50 bytes; 6 is optimal balance * - **Security**: Validates all inputs in normal cases * - **sCrypt constraint**: Bitcoin Script loops must be unrolled at compile time * * ## Security Implications * Transactions with more than 6 inputs will be **rejected by the contract**. * This prevents attackers from hiding duplicate scriptHashes in unchecked input * indices beyond the validation limit. * * @constant * @see {@link Genesis.checkDeploy} - Uses this constant for input validation * @category Genesis */ export declare const MAX_GENESIS_CHECK_INPUT = 6; /** * Maximum number of outputs to check during genesis deployment. * * ## Purpose * Limits the number of outputs validated during deployment to match input * validation coverage and support typical deployment patterns. * * ## Usage Scenarios * - **1 output**: Deploy single contract * - **2-3 outputs**: Deploy contract + change outputs * - **4-6 outputs**: Multi-contract deployment or complex output structures * * ## Validation Scope * Only `output[0]` must be unique. Other outputs (1-5) can have duplicate * scriptHashes as long as they differ from `output[0]`. * * @constant * @see {@link Genesis.checkDeploy} - Uses this constant for output validation * @see {@link MAX_GENESIS_CHECK_INPUT} - Corresponding input limit * @category Genesis */ export declare const MAX_GENESIS_CHECK_OUTPUT = 6; /** * Genesis contract for validating initial deployment outputs. * * ## Purpose * The Genesis contract ensures that deployed contracts have unique scriptHashes, * preventing duplicate deployments and establishing a verifiable deployment origin. * It acts as a "genesis UTXO" that validates the first deployment of a contract. * * ## Deployment Validation Rules * 1. **Genesis position**: Genesis must be unlocked at input index 0 * 2. **Output uniqueness**: Contract at `output[0]` must have unique scriptHash among all outputs * 3. **Input differentiation**: Contract at `output[0]` must differ from all input scriptHashes * 4. **Input limit**: Transaction must have ≤ {@link MAX_GENESIS_CHECK_INPUT} inputs * 5. **Output limit**: Transaction must specify ≤ {@link MAX_GENESIS_CHECK_OUTPUT} outputs * * ## Why output[0]? * Only `output[0]` requires uniqueness validation. This design allows: * - Deploying the **primary contract** at output[0] with guaranteed uniqueness * - Including **auxiliary contracts** or **change outputs** at indices 1-5 * - **Multi-output deployments** where only the main contract needs uniqueness * * ## Empty Placeholders * When fewer than {@link MAX_GENESIS_CHECK_OUTPUT} outputs exist, use empty * placeholders (scriptHash = empty ByteString) for unused slots. These are * ignored during validation. * * @example * **Basic single contract deployment:** * ```typescript * import { Genesis, genesisCheckDeploy } from '@opcat-labs/scrypt-ts-opcat'; * import { ExtPsbt } from '@opcat-labs/scrypt-ts-opcat'; * * // 1. Create and bind Genesis contract * const genesis = new Genesis(); * genesis.bindToUtxo(genesisUtxo); * * // 2. Create the contract to deploy * const minter = new CAT20Minter(...); * * // 3. Build deployment transaction * const psbt = new ExtPsbt({ network }) * .addContractInput(genesis, genesisCheckDeploy()) // Genesis validates deployment * .addContractOutput(minter, 1000n) // Deploy at output[0] * .change(changeAddress, feeRate) * .seal(); * * // 4. Finalize and broadcast * await psbt.finalizeAllInputs(); * const txid = await psbt.broadcast(); * console.log(`Contract deployed at ${txid}:0`); * ``` * * @category Contract * @category Genesis * @see {@link genesisCheckDeploy} - Helper function for easier deployment * @see {@link MAX_GENESIS_CHECK_INPUT} - Maximum inputs validated * @see {@link MAX_GENESIS_CHECK_OUTPUT} - Maximum outputs validated * @onchain */ export declare class Genesis extends SmartContract { constructor(); /** * Validates the deployment transaction outputs. * * ## Validation Process * This method performs a **two-phase validation**: * * **Phase 1: Output Serialization & Uniqueness** (lines 168-183) * - Iterates through all outputs up to MAX_GENESIS_CHECK_OUTPUT * - Serializes valid outputs (index < outputCount) for context matching * - Validates `output[0]` scriptHash is unique among all outputs * - Ensures no duplicate contracts are deployed in a single transaction * * **Phase 2: Input Differentiation** (lines 185-195) * - Checks `output[0]` differs from all input scriptHashes * - Prevents redeployment attacks using existing contract UTXOs * - Validates only inputs within MAX_GENESIS_CHECK_INPUT limit * * ## Why Two Separate Loops? * 1. **Output loop**: Dual-purpose (serialize + validate uniqueness) * 2. **Input loop**: Independent validation after outputs are processed * 3. **sCrypt constraint**: Loops must be unrolled at compile time * * @param outputs - Fixed array of 6 outputs; fill unused slots with empty placeholders * @param outputCount - Number of actual outputs (1-6); outputs beyond this are ignored * * @throws {Error} 'Genesis must be unlocked at input index 0' - Genesis not at input 0 * @throws {Error} 'Too many inputs to validate' - More than MAX_GENESIS_CHECK_INPUT inputs * @throws {Error} 'Invalid outputCount' - outputCount out of range [1, 6] * @throws {Error} 'Output scriptHash must be non-empty' - Empty scriptHash in valid output * @throws {Error} 'output[0] must be unique among all outputs' - Duplicate scriptHash in outputs * @throws {Error} 'output[0] must differ from all input scriptHashes' - Matches an input * @throws {Error} 'Outputs mismatch with the transaction context' - Serialization mismatch * * @example * ```typescript * // Advanced: Direct method call (most users should use genesisCheckDeploy helper) * const genesis = new Genesis(); * genesis.bindToUtxo(genesisUtxo); * * // Create output array with empty placeholders * const outputs: TxOut[] = [ * { scriptHash: sha256(contractScript), satoshis: 1000n, dataHash: sha256('') }, * ...fill({ scriptHash: toByteString(''), satoshis: 0n, dataHash: sha256('') }, 5) * ]; * * await genesis.methods.checkDeploy( * outputs as FixedArray, * 1n // Only 1 real output, rest are placeholders * ); * ``` * * @see {@link genesisCheckDeploy} - Helper function for easier usage * @see {@link MAX_GENESIS_CHECK_INPUT} - Maximum inputs validated * @see {@link MAX_GENESIS_CHECK_OUTPUT} - Maximum outputs validated * @onchain */ checkDeploy(outputs: FixedArray, outputCount: bigint): void; } /** * Creates a contract call function for Genesis.checkDeploy that automatically * builds the TxOut array from transaction outputs. * * ## What it does * This helper function simplifies Genesis deployment by: * 1. **Extracting outputs** from the PSBT transaction * 2. **Computing hashes** (scriptHash and dataHash) for each output * 3. **Creating placeholders** for unused output slots (up to 6 total) * 4. **Invoking checkDeploy** with properly formatted parameters * * ## When to use * - **Recommended**: Use this helper when building deployment transactions with ExtPsbt * - **Advanced**: Call {@link Genesis.checkDeploy} directly for manual control * * ## Output Handling * - Processes up to {@link MAX_GENESIS_CHECK_OUTPUT} (6) outputs * - Automatically limits `outputCount` via `Math.min(txOutputs.length, 6)` * - Fills unused slots with empty placeholders (scriptHash = empty ByteString) * * @returns A ContractCall function compatible with ExtPsbt.addContractInput * * @example * **Basic single contract deployment:** * ```typescript * import { Genesis, genesisCheckDeploy } from '@opcat-labs/scrypt-ts-opcat'; * import { ExtPsbt } from '@opcat-labs/scrypt-ts-opcat'; * * // 1. Setup Genesis contract * const genesis = new Genesis(); * genesis.bindToUtxo(genesisUtxo); * * // 2. Create contract to deploy * const minter = new CAT20Minter(...); * * // 3. Build deployment transaction * const psbt = new ExtPsbt({ network }) * .addContractInput(genesis, genesisCheckDeploy()) // Genesis validates * .addContractOutput(minter, 1000n) // Deploy at output[0] * .change(changeAddress, feeRate) // Change output * .seal(); * * // 4. Finalize and broadcast * await psbt.finalizeAllInputs(); * const txid = await psbt.broadcast(); * console.log(`Contract deployed at ${txid}:0`); * ``` * * @example * **Multi-output deployment:** * ```typescript * // Deploy primary contract + auxiliary contracts * const psbt = new ExtPsbt({ network }) * .addContractInput(genesis, genesisCheckDeploy()) * .addContractOutput(primaryContract, 2000n) // output[0] - must be unique * .addContractOutput(helperContract, 1000n) // output[1] - can match output[2+] * .addContractOutput(anotherHelper, 1000n) // output[2] - can match output[1] * .change(changeAddress, feeRate) * .seal(); * ``` * * @example * **Error handling:** * ```typescript * try { * const psbt = new ExtPsbt({ network }) * .addContractInput(genesis, genesisCheckDeploy()) * .addContractOutput(contract1, 1000n) // output[0] * .addContractOutput(contract1, 1000n) // ❌ Same as output[0] - will fail! * .seal(); * await psbt.finalizeAllInputs(); * await psbt.broadcast(); * } catch (error) { * // Error: output[0] must be unique among all outputs * console.error('Deployment failed:', error.message); * } * ``` * * @category Genesis * @see {@link Genesis.checkDeploy} - The underlying contract method * @see {@link MAX_GENESIS_CHECK_OUTPUT} - Maximum outputs validated */ export declare function genesisCheckDeploy(): ContractCall; //# sourceMappingURL=genesis.d.ts.map