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

    Class Script

    Virtual Hash Time Lock Contract (VHTLC) script implementation.

    VHTLC enables atomic swaps and conditional payments in the Arkade protocol. It provides multiple spending paths:

    • claim: Receiver can claim funds by revealing the preimage
    • refund: Sender and receiver can collaboratively refund
    • refundWithoutReceiver: Sender can refund after locktime expires
    • unilateralClaim: Receiver can claim unilaterally after delay
    • unilateralRefund: Sender and receiver can refund unilaterally after delay
    • unilateralRefundWithoutReceiver: Sender can refund unilaterally after delay
    • nonInteractiveClaim (with nonInteractiveParameters): server + emulator can push the receiver's claim, pinned to a pre-committed destination
    • nonInteractiveRefund (with nonInteractiveParameters): server + receiver
      • emulator can push the sender's refund immediately, no timelock, pinned to a pre-committed destination — recoverable even if the sender's own key is lost
    • nonInteractiveRefundWithoutReceiver (with nonInteractiveParameters): server + emulator can push the sender's refund after refundLocktime, pinned to a pre-committed destination — the only refund tier needing no participant signature at all

    See ScriptV2 for the current recommended construction — same leaf ladder, same options shape, an added length check on the claim preimage. This class is unchanged and stays available as-is.

    Pre-existing limitation: the vhtlc contract handler registers none of the covenant leaves. nonInteractiveParameters builds on this class exactly as it does on ScriptV2 — both extend the same BaseScript where those leaves are constructed. But the vhtlc contract handler (src/contracts/handlers/vhtlc.ts) round-trips none of them: its params type carries no covenant fields, and createScript only ever builds the six signature-only leaves. A V1 script built with the covenant suite therefore compiles and can be funded, but cannot be registered as a vhtlc contract — the handler would derive a different (six-leaf) script for the same params and ContractManager refuses the mismatch. Register through the vhtlc-v2 handler instead, which round-trips the suite.

    const vhtlc = new VHTLC.Script({
    sender: alicePubKey,
    receiver: bobPubKey,
    server: serverPubKey,
    preimageHash: hash160(secret),
    refundLocktime: BigInt(chainTip + 10),
    unilateralClaimDelay: { type: 'blocks', value: 100n },
    unilateralRefundDelay: { type: 'blocks', value: 102n },
    unilateralRefundWithoutReceiverDelay: { type: 'blocks', value: 103n }
    });

    Hierarchy

    • BaseScript
      • Script
    Index

    Constructors

    Properties

    claimScript: string
    leaves: TapLeafScript[]
    nonInteractiveClaimArkadeScript?: Bytes
    nonInteractiveClaimScript?: string
    nonInteractiveRefundArkadeScript?: Bytes
    nonInteractiveRefundScript?: string
    nonInteractiveRefundWithoutReceiverArkadeScript?: Bytes
    nonInteractiveRefundWithoutReceiverScript?: string
    options: VHTLC.Options
    pkScript: Bytes
    refundScript: string
    refundWithoutReceiverScript: string
    scripts: Bytes[]

    Raw tapscript bytes for each leaf

    tweakedPublicKey: Bytes
    unilateralClaimScript: string
    unilateralRefundScript: string
    unilateralRefundWithoutReceiverScript: string

    Methods

    • Build the Arkade address corresponding to this virtual output script.

      Parameters

      • prefix: string = DEFAULT_NETWORK.hrp

        Bech32 human-readable prefix

      • serverPubKey: Bytes

        32-byte Arkade server public key

      Returns ArkAddress

      Arkade address for this script

      ArkAddress

    • Encode the virtual output script to a TapTree byte representation.

      Returns Bytes

      Encoded TapTree bytes

      decode

    • Look up a tapleaf script by its hex-encoded tapscript body.

      Parameters

      • scriptHex: string

        Hex-encoded tapscript body without the leaf version byte

      Returns TapLeafScript

      Matching tapleaf script

      Error if no matching leaf exists

    • Return the timelocked non-interactive refund tapleaf and its ArkadeScript.

      SPENDING THIS LEAF, CONCRETELY — confirmed from this SDK's own emulator client and covenant-spend builder (EmulatorProvider in src/providers/emulator.ts, and ArkadeTransactionBuilder in src/arkade/contract.ts), which is the general machinery every covenant leaf in this file goes through:

      1. Build the ark tx spending this leaf (this method's TapLeafScript as tapLeafScript, this script's VtxoScript.encode as tapTree), plus its checkpoint tx.
      2. Attach the ArkadeScript this method returns to the spent input via an EmulatorPacket (type 1) — { vin, script: <this ArkadeScript>, witness: <empty> }, empty because the script pushes its own input/output index with PUSHCURRENTINPUTINDEX rather than reading one from the witness — wrapped in an Extension OP_RETURN output on the ark tx.
      3. Attach the spent input's OWN creating ark tx as PrevArkTx on input 0 — required so the emulator can resolve that input's prevout pkScript/value; it does not otherwise have them.
      4. POST the (base64-PSBT) ark tx and checkpoint(s) as { arkTx, checkpointTxs } to the emulator's POST /v1/tx.

      THE COVENANT CHECK the emulator runs against that ArkadeScript — enforcePayTo(senderPkScript), see that function above — is: the output at this SAME input's index is a v1 P2TR output paying senderPkScript, with a value at least the input's. Only on that check passing does the emulator sign for nirCosigner (the emulatorPubkey tweaked by this ArkadeScript's hash); the response carries the fully co-signed signedArkTx and signedCheckpointTxs — ArkadeTransactionBuilder.send()'s own comment on this path: "the emulator executes the arkade script and finalizes with arkd" — no separate call to arkd is made by this SDK for a covenant spend. Neither server nor receiver play any part in that check: this leaf's tapscript still requires server's own signature alongside nirCosigner's (see the class doc above), but that is consensus-level multisig, not something the covenant enforces.

      NOT SPENDABLE UNTIL refundLocktime MATURES — the tapscript's OP_CHECKLOCKTIMEVERIFY is arkd's concern, not the emulator's; the emulator will happily co-sign an immature spend and arkd will then refuse it. A block-height-typed refundLocktime (below the standard height/timestamp boundary this SDK names CLTV_HEIGHT_THRESHOLD, 500,000,000, in src/contracts/handlers/helpers.ts) is refused by arkd for a forfeit-eligible leaf independent of maturity — use a seconds-typed (absolute Unix timestamp) value.

      Returns [TapLeafScript, Bytes]

    • Build the Taproot onchain address corresponding to this virtual output script.

      Parameters

      • network: BTC_NETWORK = DEFAULT_NETWORK

        Bitcoin network descriptor

      Returns string

      Taproot onchain address

      address

    • Decode a virtual output script from an encoded TapTree.

      Parameters

      • tapTree: Bytes

        Encoded TapTree bytes

      Returns VtxoScript

      Decoded virtual output script

      Error if the TapTree cannot be decoded into a valid script set

      encode