Kaspa Deposit lets one party lock KAS in an on-chain covenant for a fixed term while another party holds a claim window to dispute. The twist: it uses the exact same contract as Kaspa Escrow — ten spending paths on Toccata mainnet — with one difference. Instead of writing new code, Deposit swaps who plays which role.
No new contract. No new audit surface. Just a role inversion and a two-phase timer.
Why Not Write a New Contract?
Every new on-chain contract is a new thing to audit, a new binary to deploy, and a new set of edge cases to discover. If the existing escrow covenant already encodes the right primitives — two parties, an arbiter, a time-based fallback, constrained outputs — then a deposit instrument is not a different problem. It is the same problem with labels swapped.
The practical payoff is a single audit surface. The single-input invariant, the fee-budget griefing cap, the value-conservation checks — all the guards audited for escrow apply identically to Deposit, because the bytecode is literally the same file. Maintenance is also shared: a fix to the covenant or the WASM builder benefits every deal template that runs on top of it.
Role Inversion: Same Covenant, Different Semantics
The escrow.sil contract defines three pubkey slots: buyer, seller, and arbiter. Every spending path routes funds to buyer, seller, or a split between them, with a fee deducted to a fixed feeSpk address. There are ten paths in total — the full map is covered in Kaspa Escrow's spending paths.
Role inversion: mapping the public "depositor" to the contract's seller parameter and the public "holder" to the contract's buyer parameter, so that the same spending-path semantics produce deposit behavior instead of trade behavior.
The mapping at deal creation looks like this:
EscrowParams {
buyer: holder_pubkey, // public "holder" → contract buyer
seller: depositor_pubkey, // public "depositor" → contract seller
arbiter: arbiter_pubkey,
timeoutTo: 1, // timeout → seller → depositor
...
}
Setting timeoutTo = 1 (seller) ensures that when the arbiter deadline expires, funds go to the depositor — the party who put up the collateral — rather than the party claiming it.
Here is how each path's meaning changes under inversion:
| Path | Escrow meaning | Deposit meaning |
|---|---|---|
release(buyerSig) | Buyer confirms → seller paid | Holder releases → depositor gets funds back |
refund(sellerSig) | Seller returns → buyer | Depositor waives → holder receives deposit |
dispute(buyerSig) | Buyer opens a dispute | Holder opens a claim |
autoRelease() | No dispute in window → seller paid | No claim in window → depositor gets funds back |
arbitrateToSeller(arbSig) | Arbiter pays seller | Arbiter pays depositor |
arbitrateToBuyer(arbSig) | Arbiter pays buyer | Arbiter pays holder |
arbitrateSplit(arbSig) | Arbiter splits | Arbiter splits between depositor and holder |
timeoutToSeller() | Arbiter gone → seller | Arbiter gone → depositor |
timeoutToBuyer() | Arbiter gone → buyer | Arbiter gone → holder |
mutual(b+sig, s+sig) | Both agree freely | Both agree freely (any split or destination) |
The mutual path deserves attention. It requires both signatures and allows arbitrary output distribution — but still must include the fee output (an anti-avoidance guard in the covenant). In a deposit scenario, this means depositor and holder can agree on any settlement without involving the arbiter: full return, partial split, even a redirect to a third address, as long as the service fee is paid.
Two Phases: Term and Claim Window
A deposit has two sequential time intervals, both measured in DAA scores — Kaspa's on-chain difficulty-adjusted clock that counts blue and merged-red blocks (Kaspa wiki):
Term — a free-form duration chosen by the depositor at creation. During this period, the deposit simply sits in its covenant UTXO. Neither party can trigger a dispute through the on-chain contract. Think of it as the quiet period where the collateral is locked and everyone waits.
Claim window — a preset duration chosen from a whitelist of values (24, 48, 72, 96, 120, or 168 hours, expressed in DAA scores). This is the window in which the holder can open a claim by submitting a dispute transaction signed with the holder's key. If the holder opens a claim, the deal enters DISPUTED mode — identical to escrow — and an arbiter deadline starts ticking.
If the claim window expires without a claim, the watcher broadcasts autoRelease, and the depositor's funds return to them. The total time before this happens is the sum of the term and the claim window.
If a claim is opened and the arbiter deadline also expires without resolution, the timeoutToSeller path — keyless, no service fee — returns funds to the depositor. The depositor is always the fallback beneficiary.
Keyless Settlement: When Nobody Acts
The most important architectural property of Deposit is the same one that makes Kaspa Safe resilient: certain spending paths require no signature at all.
autoRelease() needs only age >= disputeWindow and ACTIVE mode. timeoutToSeller() needs only age >= arbiterDeadline, DISPUTED mode, and timeoutTo == 1. Neither path checks any signature. Anyone — the depositor, the holder, the watcher, a stranger — can construct and broadcast the transaction. The funds still go exactly where the covenant dictates.
In production, the off-chain watcher polls active deals every 10 seconds, checking UTXO state and DAA score progression. When the timer expires, it broadcasts the settlement transaction automatically. The depositor receives an alert (Telegram, e-mail, or web push, if subscribed) but does not need to sign anything or even be online.
This is what makes Deposit non-custodial in practice, not just in theory. If the Kaspa Forge service goes offline permanently, the depositor can recover funds by taking the raw covenant parameters, constructing the autoRelease or timeoutToSeller transaction locally, and submitting it to any Kaspa node. The open-source CLI tool escrowctl supports this — the same offline path that serves escrow deals works unchanged for deposits.
How Kaspa Forge Implements Deposit
Deposit does not introduce a new contract binary or a separate WASM module. A deposit is a record in the shared deals database with template = "deposit". That single field tells the UI which labels to show (depositor / holder instead of buyer / seller) and which time semantics to apply (term + claim window instead of a single dispute window).
The entry point is a dedicated API module that accepts public "depositor" and "holder" labels and maps them to contract seller and buyer parameters at creation time. After creation, the deal flows through the same infrastructure as every other agreement on the platform — the shared deals registry, the E2E chat protocol (messages encrypted in the browser, anchored as on-chain transactions), the dispute pipeline, the AI mediator for non-binding recommendations, and the human arbiter for binding decisions.
Template: a string field in the deals database that tells the front end and watcher which role labels and time semantics to apply, without altering the underlying covenant bytecode.
On the front end, the Desk shows Deposits in their own tab with deposit-specific terminology. The React routes live in a dedicated feature module but share the same WASM core (vault-core-v5) and the same encrypted Desk profile. Private keys are derived from the HD master seed using the same HMAC-SHA512 domain-separation scheme that powers Safe, Escrow, and Marketplace — one seed, multiple instruments, keys never leave the browser.
The fee structure is inherited directly from escrow: 0.5% (minimum 1.2 KAS) on resolve, 2% (minimum 5 KAS) on dispute. The feeBudget parameter — the covenant-level cap on network fees, bounded between 0.01 and 0.1 KAS — is set at creation time and enforced on-chain. The timeout path carries zero service fee. Minimum deal size is 50 KAS; there is no upper cap.
Security Inherited, Limitations Shared
By reusing the escrow covenant, Deposit inherits every security property that has been audited for that contract:
- Single-input invariant. Every spending path begins with
require(tx.inputs.length == 1), closing the multi-UTXO siphon vector where two UTXOs sharing a P2SH address could leak the smaller one's value into fees. - Fee-budget griefing cap.
require(feeBudget > 0 && feeBudget <= MAX_FEE_BUDGET)on all paths exceptmigrate(which requires both signatures, so the owner controls fees directly). This prevents a watcher or any third party from burning the deposit in an inflated network fee on keyless paths. - Value conservation. Constrained paths verify the first output and its value floor, ensuring the deposit amount cannot be siphoned.
The known v3 covenant limitation also applies: constrained paths check outputs[0] and its value but do not enforce outputs.length. The official builders always construct canonical single-output transactions, and the feeBudget cap (0.01–0.1 KAS) bounds any potential leakage in a hypothetical second output. This is a documented trade-off; an exact-output guard is planned for a future covenant version.
And like escrow, Deposit depends on a human arbiter for binding dispute resolution. The AI mediator provides a non-binding recommendation based on chat transcripts and evidence, but the arbitrateTo* signature comes from a person holding an offline key. If that person becomes unreachable, the covenant's timeout path — no signature, no fee, funds to depositor — is the safety net. The depositor is always protected by the clock.
---
Kaspa Deposit runs on the same covenant and infrastructure as Kaspa Escrow — on-chain operations are free forever, contracts and tooling are open source. You can explore the Deposit tab inside Desk, the same encrypted browser profile that also holds your vaults and escrow deals. The non-custodial design means funds remain yours even if the service disappears.
FAQ
What is Kaspa Deposit?
A non-custodial instrument where one party locks KAS in an on-chain covenant for a fixed term, and another party gets a claim window to open a dispute. If no claim is made, funds return to the depositor automatically.
Does Deposit use a different smart contract than Escrow?
No. It uses the same 10-path escrow.sil covenant on Kaspa's Toccata mainnet. The only difference is role mapping: the depositor takes the contract's seller role, and the holder takes the buyer role.
Can the depositor lose their deposit?
Only if the holder opens a claim within the claim window and the arbiter rules in the holder's favor, or the depositor voluntarily releases via the refund path. The covenant guarantees funds can only go to the depositor, the holder, or the fixed fee address — never to a third party.
What happens if nobody acts on the deposit?
After the claim window expires, the off-chain watcher broadcasts a keyless autoRelease transaction that returns funds to the depositor. No signature from either party is required.
Is Kaspa Deposit non-custodial?
Yes. Funds live in an on-chain covenant; private keys live only in the browser. If the service disappears, the timeout path returns the deposit to the depositor without any server involvement.
What are the fees?
Same as escrow: 0.5% (min 1.2 KAS) on resolve, 2% (min 5 KAS) on dispute. The timeout path — used when the arbiter becomes unreachable — carries zero service fee.
Put your KAS where theft can be cancelled
A covenant vault on Kaspa mainnet: your keys, your rules, our tooling. Free on-chain, forever.
Create a vault
