Skip to main content
This tutorial builds one savings vault on mainnet. Paste the blocks into vault.ts in order. Savings is a fixed-party vault, and funding pins the parties (Arkade Vaults). The escrow is the case with more than one party.

Setup

You need Rust 1.85 or newer and Node.js 22.13 or newer (below 27). Set type to module in package.json. The compiler page describes the language.
The service selects the operator, the indexer, Esplora, and the emulator.
vault.ts
For another deployment, give the client the server URL and the emulator URL. Without an emulator URL, covenant paths stay off.

Create a Vault

release pays one output to recipientScript after the emulator clock passes unlockAt. unilateral is the signature of the owner. It works after you unroll the output and the exit delay of the operator ends. The client binds serverExitDelay, so do not pass an argument for it.
savings_vault.ark
Load the artifact that you committed. The SDK function programFromArtifact reads the output of arkadec. The function parseArtifact reads a different format. The address depends on the exit delay that the operator reports when you create the contract. The client binds serverExitDelay from that value (CSV delays). If the delay changes, a new contract from the same artifact and arguments has another address. Register the contract, because the stored row keeps the delay (Watch and persist). For a bytes32 payout, use the 32-byte witness program (vtxoTaprootKey).
An argument is a Uint8Array, a bigint, or a number. A bool is 0 or 1. A child contract that you create with new in the source binds as contract_<Name>_<args>. The value is the 32-byte witness program of the child.

Watch and persist

Connect the client with a contract repository or with the contract manager of a wallet (Setup). Pass contractRepository only. The Storage page builds that repository for Node. A repository in memory loses the row when the process exits. A subscription registers the contract. It reports vtxo_received, vtxo_spent, and connection_reset after you subscribe. A subscription does not replay earlier outputs, and after a reconnect it does not report the missed events. Read the stored virtual outputs after you subscribe and after each connection_reset. The stored virtual outputs include the spent virtual outputs. fromContract builds a contract again from its stored keys and arguments. The address stays the same after a signer rotation or a change of the exit delay.

Spend

The spend takes one contract output. .from(output) places that output at input 0. Other inputs are sibling outputs when the function needs them, for example an oracle output or a standing offer. The savings vault and the escrow assert a single input. The output script is the full pkScript, not the witness program that you gave to the constructor. Send funds to the printed address first. This spends real sats.
The identity signs input 0 only when its key is in the leaf of the function. The identity also signs each funded input. A covenant send goes to the emulator (submitTx). The emulator runs the Arkade Script and cosigns only when the script passes. The client then submits the transaction to the operator and finalizes it. A tapscript send goes to the operator (submitTx, then finalizeTx). A signature argument is a BIP340 Schnorr signature of the message. Two covenant inputs need one emulator entry each. A contract output expires with its batch, as other outputs do (virtual output management).

CSV delays

An exit leaf passes serverExitDelay to older. Do not pass an argument for it, because the client binds the exit delay that the operator reports. Before the operator renews an output in a batch, the output needs an older leaf. Keep the artifact and the constructor arguments. Register the contract. The stored row keeps the exit delay. To use a longer delay, declare an integer parameter and pass it to older. A parameter binds as a raw BIP68 sequence. The operator rejects a block sequence on an exit leaf, except on regtest. Use seconds. The value must be a multiple of 512 and at least the exit delay of the operator. The operator reports unilateralExitDelay in seconds when the value is 512 or more. Otherwise, it reports blocks.