A vault that lets you withdraw funds instantly is just a wallet. A vault that forces your withdrawal to sit in a waiting period — long enough for you to spot a thief and hit cancel — is something more. But for that waiting period to work on-chain, the contract needs a clock.
Kaspa's Toccata covenants don't have access to your phone's timestamp or a centralized oracle. What they do have is DAA score — a protocol-level counter that advances with every block in the DAG. Covenant scripts read a UTXO's age: the DAA score difference between the current virtual block and the moment the UTXO was created. When age crosses a threshold, a time-locked spending path opens.
This one mechanic — UTXO age measured in DAA score — is the clock behind every timed covenant feature on Kaspa: withdrawal delays, inheritance dead-man switches, escrow dispute windows, and automatic releases. This article explains how it works, where it's used, and what the trade-offs are.
DAA score: the DAG's internal clock
The Kaspa wiki defines DAA score as the running count of blue blocks plus all merged red blocks — a monotonically increasing number tied to the emission schedule. Unlike raw block height, DAA score accounts for the DAG structure: it advances even when multiple blocks are produced in parallel, as happens routinely at 10 blocks per second.
DAA score — a consensus-level counter equal to blue score plus the cumulative count of red blocks that have been successfully merged and rewarded. It increments by at least one per accepted block and serves as Kaspa's canonical time reference.
Why does this matter for covenants? Because a UTXO's age — the delta between the current virtual DAA score and the DAA score at which the UTXO was created — is a value any covenant script can inspect at spending time. No external data feed required, no oracle, no trusted timestamp server.
The age primitive in covenant scripts
When a Kaspa transaction creates a UTXO, that UTXO is stamped with the DAA score of the accepting block. When a future transaction tries to spend it, the virtual block's DAA score is compared against the stamp. The difference is the UTXO's age.
Covenant scripts inspect this through transaction introspection opcodes. A contract can require age >= N before allowing a particular spending path. If the condition isn't met, that path simply isn't available — every node on the network rejects the transaction.
; Conceptual — not exact syntax:
; The "complete" path only becomes spendable
; after the UTXO has aged past the delay threshold
entrypoint complete():
require(age >= delay)
; destination was fixed at initiate() time
; no signature needed — keyless path
This gives covenant designers a fundamental building block: a time constraint enforced by proof-of-work consensus, not by any third party.
How the vault uses age: three time-locks
In Kaspa Safe, the covenant contract (vault.sil) implements three distinct time-locks, all driven by UTXO age.
Withdrawal delay. When you initiate a withdrawal from your vault, the contract transitions from VAULT mode to UNVAULTING and locks the destination address into on-chain state. The complete() path — which actually releases funds — requires age >= delay. During that window, anyone with the alarm key can broadcast cancel() to send the UTXO back to vault mode.
initiate(hotSig, destPk) → VAULT → UNVAULTING (age resets to 0)
cancel(alarmSig) → UNVAULTING → VAULT (age resets to 0)
complete() → UNVAULTING → dest (age >= delay, no sig)
The delay is chosen by the vault owner at creation — 24 hours for active users, 72 hours for deeper cold storage. The critical design point: complete() requires no signature. It's a keyless path. Once the delay expires, anyone can broadcast it. The funds go exactly where initiate fixed them; no one can redirect them.
Inheritance timer. The vault has a separate inheritDelay parameter, typically weeks or months. If the owner doesn't checkin() within that window, an inheritance path opens. The autoInherit flag selects the mode:
autoInherit == 1:inheritAuto()— keyless, requiresage >= inheritDelay. Anyone can broadcast; funds go to the heir's hardcoded address.autoInherit == 0:inheritSigned(heirSig)— requires the heir's signature andage >= inheritDelay. The heir must actively claim.
If the owner sets heir to 32 zero bytes, inheritance is disabled entirely.
The checkin heartbeat. The checkin() path consumes the vault UTXO and recreates it at the same address with the same parameters. The new UTXO's age starts from zero. No funds move, no parameters change, but the clock resets.
checkin(hotSig) → VAULT → VAULT (age resets; inheritance timer restarts)
In production, Kaspa Safe sends reminders when 80% of the inheritDelay has elapsed — through Telegram, email, or web push — so the owner knows to checkin before the heir path activates.
How escrow uses age: dispute windows and timeouts
The escrow contract (escrow.sil) uses the same UTXO age primitive for two different purposes — one optimistic, one defensive.
Dispute window and auto-release. After an escrow deal is funded, the buyer has a window (measured in DAA score units) to file a dispute. If no dispute arrives and age >= disputeWindow, the autoRelease() path fires: a keyless transaction that sends all funds to the seller. Presets range from 24 hours for OTC trades to 168 hours for physical goods.
autoRelease() → ACTIVE, age >= disputeWindow → funds to seller (keyless, fee applies)
This is the optimistic path: if both parties are satisfied, the money moves automatically without anyone touching a button.
Arbiter deadline and timeout. Once a dispute is filed (the UTXO transitions to DISPUTED mode), a fresh UTXO is created and age resets. Now a second clock starts: arbiterDeadline. If the arbiter fails to sign a verdict within this window, the timeout path activates — sending funds to the pre-agreed party (buyer or seller, set at deal creation) with zero service fee.
timeoutToBuyer() → DISPUTED, timeoutTo==0, age >= arbiterDeadline → buyer (no fee)
timeoutToSeller() → DISPUTED, timeoutTo==1, age >= arbiterDeadline → seller (no fee)
The timeout mechanism is a deliberate safety net: even if every service and every human disappears, the contract eventually releases funds on its own. The zero-fee design ensures a motivated third party (or the beneficiary themselves) can broadcast the transaction without cost considerations.
How Kaspa Forge monitors these clocks
On-chain, the covenant enforces time-locks unconditionally. Off-chain, the Kaspa Forge platform watches and alerts.
The server-side watcher runs a 10-second polling cycle, checking the DAA score and UTXO state of every registered vault and escrow deal. When thresholds approach, notifications go out through all configured channels — Telegram, email, and web push — with escalating urgency:
- Vault owner: "80% of your inheritance delay has elapsed — checkin now to reset the timer."
- Vault owner: "A withdrawal has been initiated. You have X hours to cancel with your alarm key."
- Escrow buyer: "50% of the dispute window has passed. Release or dispute before auto-release."
- Heir contact: Email notification that the inheritance path is about to open.
The watcher can also broadcast keyless transactions (complete(), autoRelease(), autoInherit()) automatically. Since these paths enforce the destination on-chain — the money goes where the contract says, not where the broadcaster says — the watcher has no ability to redirect funds. This is what makes the automation safe: the broadcaster is a messenger, not a decision-maker.
Trade-offs and honest limitations
DAA score as a clock is not perfect. Here are the real constraints.
Granularity vs. wall time. DAA score advances roughly proportionally to block rate, but it's not a wall clock. At 10 BPS, a "24-hour" delay is approximately 864,000 DAA score units. Actual elapsed time may drift by minutes or even hours depending on network hashrate fluctuations, since difficulty adjustment smooths over windows of 2,641 blocks rather than tracking real time. For security purposes — theft detection windows, dispute periods — this variance is acceptable. For precise scheduling, it isn't.
No countdown visible on-chain. There's no on-chain oracle that says "this UTXO has 4 hours remaining." Nodes compute age at validation time, but the remaining time for a specific path is a client-side calculation: current virtual DAA score minus UTXO DAA score. The Kaspa Forge UI computes this in the browser against live node data.
Checkin has a cost. Each checkin() is a transaction that consumes a small amount of KAS in network fees. For vault owners who set short inheritDelay values, the checkin burden can add up. The platform sends reminders to minimize unnecessary checkins while preventing accidental inheritance triggers.
Age resets on any spend. If the vault owner initiates a withdrawal — even one they plan to cancel — the UTXO's age resets when it returns to VAULT mode. This means a cancelled withdrawal also resets the inheritance timer. In practice this is rarely problematic: if you're actively using the vault, you're clearly alive. But it's worth understanding the interaction.
DAA score, not block height. This is actually an advantage over chains that use raw block height. In a blockDAG with parallel blocks, block height alone is ambiguous — whose perspective? DAA score, as a merged count of all rewarded blocks, provides a canonical monotonic counter that works across the DAG's topology. It's one of the things that makes time-locked covenants feasible on Kaspa specifically.
Try it yourself. Kaspa Safe lets you create a vault with a withdrawal delay and optional inheritance timer — both driven by the DAA score time-lock described here. The contract is open source, on-chain operations are free, and you can recover everything from a terminal if the service ever goes offline.
Putting it together
DAA score is not just an emission parameter or a difficulty reference. It's the heartbeat of every covenant-based financial contract on Kaspa. The vault's theft-protection delay, the inheritance dead-man switch, the escrow's dispute window, and the automatic release after inactivity all rely on the same fundamental primitive: require(age >= threshold).
The more blocks Kaspa produces, the more granular the clock. At 10 BPS, a 24-hour window spans roughly 864,000 blocks — far more granular than Bitcoin's ~144 blocks per day, without the security trade-offs of longer block times. The trade-off is that covenant clocks measure block-time, not wall-time. For the financial contracts Kaspa Forge builds — theft detection, inheritance, dispute resolution — this is more than sufficient.
Understanding this one mechanism unlocks the reasoning behind every timed feature in Kaspa Safe, Kaspa Escrow, and the wider Toccata covenant ecosystem.
FAQ
What is DAA score in Kaspa?
DAA score is a monotonically increasing counter equal to blue score plus the cumulative count of merged red blocks. It advances by roughly one per accepted block and serves as Kaspa's canonical consensus-level time reference.
How do covenants measure time?
Covenant scripts inspect a UTXO's age — the DAA score difference between the current virtual block and the block that created the UTXO. When age exceeds a threshold, a time-locked spending path becomes available.
Why not use wall-clock time?
Blockchains have no reliable access to wall-clock time. Block height and DAA score are the only trustworthy on-chain references. DAA score is more granular and stable across hashrate fluctuations than raw block height.
Can a covenant path require both a signature and a minimum age?
Yes. The vault's inheritSigned path, for example, requires the heir's signature and age >= inheritDelay. This combination lets contracts demand proof-of-identity and proof-of-time simultaneously.
How does the heartbeat (checkin) reset the clock?
The checkin transaction consumes the vault UTXO and recreates it at the same address with the same parameters. The new UTXO's age starts from zero, resetting the inheritance timer without moving funds.
Is DAA score affected by hashrate changes?
Kaspa's difficulty adjustment algorithm smooths out hashrate fluctuations, keeping block rate close to target. DAA score advances proportionally to block production, so short-term hashrate changes cause only minor timing drift — not the kind of multi-hour swings that affect block-height-based time-locks on slower chains.
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
