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

    Interface IContractManager

    interface IContractManager {
        advanceSigningDescriptorWatermark(index: number): Promise<void>;
        annotateVtxos(
            vtxos: VirtualCoin[],
            tapscripts?: ContractTapscriptCache,
        ): Promise<NormalizedExtendedVirtualCoin[]>;
        assertAnnotatable(
            vtxos: readonly { script: string; txid: string; vout: number }[],
        ): Promise<void>;
        assertSpendableNow?(
            vtxos: readonly AssertSpendableInput[],
            walletDescriptor?: () => Promise<string | undefined>,
        ): Promise<void>;
        createContract(params: CreateContractParams): Promise<Contract>;
        createContracts?(paramsList: CreateContractParams[]): Promise<Contract[]>;
        deleteContract(script: string): Promise<void>;
        dispose(): void;
        getAllSpendingPaths(
            options: GetAllSpendingPathsOptions,
        ): Promise<PathSelection[]>;
        getContracts(filter?: ContractFilter): Promise<Contract[]>;
        getContractsWithVtxos(
            filter?: ContractFilter,
        ): Promise<ContractWithVtxos[]>;
        getNextSigningDescriptor(): Promise<string | undefined>;
        getSpendablePaths(
            options: GetSpendablePathsOptions,
        ): Promise<PathSelection[]>;
        getSyncState(): ContractSyncState;
        getWatchedScripts?(): Promise<WatchedScript[]>;
        isWatching(): Promise<boolean>;
        onContractEvent(callback: ContractEventCallback): () => void;
        refillLookAhead(): Promise<void>;
        refreshOutpoints(outpoints: Outpoint[]): Promise<void>;
        refreshVtxos(opts?: RefreshVtxosOptions): Promise<void>;
        scanContracts(opts: ScanContractsOptions): Promise<ScanResult>;
        setContractState(script: string, state: ContractState): Promise<void>;
        setContractWatchState(
            script: string,
            watch: ContractWatchState,
        ): Promise<void>;
        unspendableNowReasons?(
            vtxos: readonly AssertSpendableInput[],
            walletDescriptor?: () => Promise<string | undefined>,
        ): Promise<Map<string, string>>;
        unwatchScript?(script: string | string[]): Promise<void>;
        updateContract(
            script: string,
            updates: Partial<Omit<Contract, "script" | "createdAt">>,
        ): Promise<Contract>;
        watchScript?(
            script: string | string[],
            options?: { label?: string },
        ): Promise<void>;
    }

    Hierarchy

    • Disposable
      • IContractManager

    Implemented by

    Index

    Methods

    • Advance the HD signing descriptor watermark to index and refill the watched look-ahead band. No-op when look-ahead/allocation is not configured.

      Parameters

      • index: number

      Returns Promise<void>

    • Stamp raw virtual outputs with the correct per-contract tapscripts (forfeit, intent, tap tree).

      Resolves each vtxo's script to its owning contract via the contract repository and attaches the matching tapscripts. Throws when any vtxo references a script with no registered contract — callers are expected to register the contract before asking for annotation. This is the single shared path that replaces scattered extendVirtualCoin* calls in wallet/handler code, and keeps the wallet from silently stamping the default tapscript onto a non-default vtxo.

      Parameters

      • vtxos: VirtualCoin[]
      • Optionaltapscripts: ContractTapscriptCache

      Returns Promise<NormalizedExtendedVirtualCoin[]>

    • Throw unless every one of vtxos still has an annotatable contract.

      Spending does not re-derive tapscripts — it uses the ones stored on the coin — so a contract that stopped being annotatable (handler no longer registered, or params its handler now rejects) still builds and submits a transaction fine, and only fails afterwards, in the bookkeeping that re-annotates the inputs. Calling this before submitting turns that into a refusal to spend, naming the contract, rather than a broadcast whose local state could not be recorded.

      Parameters

      • vtxos: readonly { script: string; txid: string; vout: number }[]

      Returns Promise<void>

    • Throw when one of vtxos belongs to a contract that provably cannot be spent right now, asking each owning handler's ContractHandler.assertSpendableNow.

      The complement of isContractGenericallySpendable, which keeps escrow out of generic selection and leaves explicit-input APIs open on purpose. This does not close that door — it makes walking through it too early report itself locally, naming the timelock, instead of coming back as a protocol-level rejection after the round trip.

      Handlers answer only where they are certain, so contracts with no opinion (which is all of them but VHTLC today) pass through untouched and cost nothing — not even a chain-tip read.

      Optional so that adding it is not a breaking change for an embedder with its own IContractManager. An implementation that omits it simply offers no opinion, which is the same answer every non-VHTLC contract gives.

      Parameters

      • vtxos: readonly AssertSpendableInput[]
      • OptionalwalletDescriptor: () => Promise<string | undefined>

      Returns Promise<void>

    • Delete a contract by script, dropping both the row and the watch. Destructive: the row is what keeps the contract's VTXOs annotatable and its transactions readable in history, so to stop watching a finished contract use setContractWatchState("retained") instead.

      Parameters

      • script: string

      Returns Promise<void>

    • List contracts with optional filters.

      Parameters

      • Optionalfilter: ContractFilter

      Returns Promise<Contract[]>

      const vhtlcs = await manager.getContracts({ type: "vhtlc" });
      const active = await manager.getContracts({ state: "active" });
    • Allocate the next signing descriptor through the manager-owned HD watermark path. Returns undefined when look-ahead/allocation is not configured.

      Returns Promise<string | undefined>

    • Rebuild the HD look-ahead watch window around the current allocation watermark. No-op when the manager was configured without lookAhead.

      Call after anything that moves the watermark (restore, boarding allocation, receive rotation, server-signer rotation). Concurrent calls coalesce into a single drain.

      Returns Promise<void>

    • Reconcile specific outpoints with the indexer's authoritative state and upsert the result into the wallet repository.

      The cursor-derived delta sync filters by created_at, so a VTXO that was created before the cursor but spent recently won't surface in a standard refreshVtxos() call. This method is the surgical recovery path for that case: when something hands us a stale outpoint (e.g. the server returns VTXO_ALREADY_SPENT with a vtxo_outpoint in its error metadata), call this to pull the latest state and unblock the caller — no full re-scan, no cursor change.

      Outpoints not owned by any tracked contract are silently dropped.

      Parameters

      Returns Promise<void>

    • Force a virtual output refresh from the indexer.

      Without options, refreshes all contracts from scratch. With options, narrows the refresh to specific scripts and/or a time window.

      Parameters

      • Optionalopts: RefreshVtxosOptions

      Returns Promise<void>

    • Explicit, gap-limit contract discovery used by wallet.restore().

      Walks HD indices from 0, asking every registered Discoverable handler whether it owns a contract anchored at that index, and registers each find via the idempotent createContract. A hit at index i (by any handler, including an injected swap handler) resets the gap counter, so swap discovery keeps the HD window open.

      Error contract (safety-critical — see spec §4):

      • A handler's discovery rejecting is collected into handlerErrors and makes its index indeterminate: it never advances the gap counter, and the scan stops verifying there rather than closing a window it never observed close. A batched Discoverable.discoverRange failure makes its whole requested range indeterminate. It still never throws.
      • A fatal operational error — materialize() throwing, or createContract rejecting — propagates out of scanContracts (it invalidates the gap-window signal, so a silent truncation would risk hiding user funds).

      Returns Promise<ScanResult>

      See ScanResult. The caller surfaces truncatedAt / handlerErrors after the inline VTXO pull.

    • Convenience helper to update only the contract's watch state.

      retained is how an owner says "this script is done": it leaves the subscription and the sweep, while the row — and so history, annotation and restore — is untouched. awaiting-funds asks for coverage only until the script is funded, after which the manager demotes it to retained itself.

      Parameters

      • script: string
      • watch: ContractWatchState

      Returns Promise<void>

      ContractWatchState

    • Which of vtxos their owning handler refuses right now, keyed by outpoint (txid:vout) and valued with the handler's own explanation.

      The predicate form of assertSpendableNow, for callers that must DROP a refused input rather than fail the batch holding it. Keyed per outpoint, not per script: a relative (CSV) timelock is measured from each coin's own confirmation, so two coins on one contract can disagree.

      Optional for the same reason assertSpendableNow is.

      Parameters

      • vtxos: readonly AssertSpendableInput[]
      • OptionalwalletDescriptor: () => Promise<string | undefined>

      Returns Promise<Map<string, string>>

    • Report VTXO activity at script without registering it as a contract, and without the wallet owning it. Activity arrives as ContractEvent vtxo_received / vtxo_spent without the contract — narrow with isContractVtxoEvent; nothing is persisted and the outputs never enter the wallet's balance, renewal or recovery paths.

      At-least-once, and re-announces on restart — the registration is in-memory, so there is no baseline to diff a restart against. Deduplicate by outpoint, and tolerate a vtxo_spent with no preceding vtxo_received — an output can be created and spent inside one gap in the stream. Re-registering a watched script is a no-op, so a caller may re-derive its whole set on a timer.

      Reports spendable outputs: a preconfirmed one counts, so a fresh funding is not missed, but one already recoverable or swept is not reported.

      Takes one script or a set. A set costs one subscription update and one indexer read however many scripts it carries, which is the difference between registering and re-registering cheaply and paying N round trips — what a service watching an address per payment does on every restart.

      Optional so adding it does not break an embedder with its own IContractManager; both shipped implementations provide it for real.

      Parameters

      • script: string | string[]
      • Optionaloptions: { label?: string }

      Returns Promise<void>