@arkade-os/sdk Documentation - v0.5.0-rc.11
    Preparing search index...

    Interface ContractHandler<P, S>

    Handler for a specific contract type.

    Each contract type (default, vhtlc, etc.) has a handler that knows how to:

    1. Create the VtxoScript from parameters
    2. Serialize/deserialize parameters for storage
    3. Select the appropriate spending path based on context
    const vhtlcHandler: ContractHandler = {
    type: "vhtlc",
    createScript(params) {
    return new VHTLC.Script(this.deserializeParams(params));
    },
    selectPath(script, contract, context) {
    const vhtlc = script as VHTLC.Script;
    const preimage = contract.data?.preimage;
    if (context.collaborative && preimage) {
    return { leaf: vhtlc.claim(), extraWitness: [hex.decode(preimage)] };
    }
    // ... other paths
    },
    // ...
    };
    interface ContractHandler<
        P = Record<string, unknown>,
        S extends VtxoScript = VtxoScript,
    > {
        type: string;
        assertSpendableNow?(
            script: S,
            contract: Contract,
            context: PathContext,
        ): void | Promise<void>;
        createScript(params: Record<string, string>): S;
        deserializeParams(params: Record<string, string>): P;
        getAllSpendingPaths(
            script: S,
            contract: Contract,
            context: PathContext,
        ): PathSelection[];
        getSpendablePaths(
            script: S,
            contract: Contract,
            context: PathContext,
        ): PathSelection[];
        isGenericallySpendable?(contract: Contract): boolean;
        selectPath(
            script: S,
            contract: Contract,
            context: PathContext,
        ): PathSelection | null;
        serializeParams(params: P): Record<string, string>;
    }

    Type Parameters

    Index

    Properties

    type: string

    Contract type managed by this handler.

    Methods

    • Refuse a spend this contract definitively cannot make right now, with a reason the caller can act on. Called before anything is signed or submitted, for inputs the caller named explicitly.

      This is the counterpart to isGenericallySpendable, not a duplicate of it. That gate keeps escrow out of GENERIC selection and deliberately leaves explicit-input APIs open, because naming an outpoint is the intent it protects. Naming one too early is still a mistake though, and without this it is a mistake the server reports — as a protocol-level rejection, after the round trip, in terms that do not name the timelock that was not yet mature.

      Throw only on a definite no. Absent, silent, or unsure all mean "no opinion" and the spend proceeds. A handler must not refuse merely because it found no path: getSpendablePaths legitimately returns empty for spendable contracts — arkade's skips every covenant leaf, so a program spendable only through its emulator-signed leaf reports nothing — and an unreadable timelock (height-typed with no chain tip) is unknown, not immature.

      Parameters

      Returns void | Promise<void>

      cltvMaturity, which keeps those apart.

      Returning a promise is allowed so a handler needing I/O is not forced to throw synchronously — callers await the result. Prefer synchronous where possible: this runs on the path between a caller's decision to spend and the spend itself.

      Error when the contract provably cannot be spent at context

    • Create the VtxoScript from serialized parameters.

      Parameters

      • params: Record<string, string>

        Serialized contract parameters

      Returns S

      Contract script instance

    • Whether this contract's VTXOs may be picked by generic wallet spending — send, settle, renewal, asset operations, offboard, available balance. Explicit-input APIs (settle({ inputs }), send({ selectedVtxos }), …) stay open regardless: naming an outpoint is the intent this gate protects.

      Pure, synchronous and offline — it runs inside the service worker, so no chain tip, no network, no live plugin object. Absent or false ⇒ NOT spendable: a type core cannot reason about must not leak by omission.

      No script parameter: deriving it costs a taproot tree per contract on a read path (#521) and no shipped handler needs it. A handler that does can call its own createScript(contract.params).

      Parameters

      Returns boolean

    • Serialize typed parameters to string key-value pairs.

      Parameters

      • params: P

        Typed contract parameters

      Returns Record<string, string>

      Serialized key-value representation