Skip to content

Delegate auto-settle limited to a 120s, single-use intent window — offline/delayed auto-settle can't work as intended #38

@aruokhai

Description

@aruokhai

Summary

Auto-delegate / auto-settle is meant to let a client delegate once and have the cosigner refresh (settle) the VTXO later — before expiry — without the client online. In practice it can perform only one settle, and only within ~120s of the client signing the delegate. Past that, the stored intent's proof-of-ownership expires and arkd rejects it (INVALID_INTENT_TIMERANGE: proof of ownership expired).

Root causes

  1. Fixed 120s intent window — the delegate intent's proof time range is hardcoded:
    • rust-sdk/ark-client/src/batch.rs:1253let expire_at = now + (2 * 60); (delegate path)
    • crates/ark/src/client/batch.rs:191let expire_at = now + 120; (boarding settle)
      The delegate is signed once and stored; when tick_auto_settle registers it >120s later, arkd rejects it.
  2. Single-use intenttick_auto_settle consumes the stored delegate (state.delegate_session.take()), and a successful settle produces a NEW VTXO with no delegate. So one delegation ⇒ at most one auto-settle.
  3. Server can't re-sign — creating a fresh intent needs the client's FROST share, so the cosigner can't autonomously re-arm the new VTXO; it depends on the client reconnecting and re-delegating.

Observed (regtest)

auto-settle drive failed: ... INVALID_INTENT_TIMERANGE (20): proof of ownership expired
  valid_at=1780137236  expire_at=1780137356  now=1780137534   (120s window, 178s late)
... clearing stored intent so client can re-delegate
  • With margin > VTXO lifetime: settles every 60s tick (intent always fresh, but wasteful loop).
  • With an intended delay > 120s: every attempt fails with proof-expired, then the client re-delegates on next refresh. Max reliable delay before settle ≈ 120s.

Impact

  • "Delegate once, stay protected offline until near expiry" does NOT hold — the cosigner can settle only within ~120s of an online delegation, once per delegation.
  • Short regtest expiries mostly self-heal via client re-delegation on refresh, but it churns error logs and burns batches.
  • Production (long VTXO expiry): a fully-closed app is unprotected beyond ~2 min after its last delegation.

Proposed directions

  1. Extend the delegate intent's expire_at to cover the settle horizon (e.g. the VTXO expires_at minus a buffer) instead of fixed 120s — subject to any max window arkd enforces (verify).
  2. Pre-sign a window / multi-use delegation so the cosigner can settle near expiry without the client.
  3. If arkd caps the proof window, reconsider the model (periodic client re-delegation; document the bounded horizon).

Files

  • rust-sdk/ark-client/src/batch.rs:1253, crates/ark/src/client/batch.rs:191 (intent expire_at)
  • cosigner-runtime/src/cosigner/handlers/auto_settle.rs (tick_auto_settle, consumes delegate)
  • cosigner-runtime/src/cosigner/handlers/ark_send.rs (settle_delegate / delegate generation)

Related: #37 (ASP-info cache after restart).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions