feat: add CovVHTLC covenant claim script and covclaim watcher daemon#396
feat: add CovVHTLC covenant claim script and covclaim watcher daemon#396Kukks wants to merge 4 commits intoarkade-script-finalfrom
Conversation
…commitment tx modification - Pass Extension output to buildForfeitTx as additionalOutputs so the IntrospectorPacket is part of the transaction from construction, preventing txid mismatch with the introspector's expected value. - Remove addIntrospectorPacketToTx for boarding commitment txs. The introspector already knows arkade scripts from the intent proof submission, so modifying the server-built commitment tx (which changes its txid) is unnecessary. - Add optional additionalOutputs parameter to buildForfeitTx and buildForfeitTxWithOutput for Extension OP_RETURN support.
arkd reconstructs forfeit txs with exactly 2 outputs (forfeit + anchor) and compares txids. Adding an Extension output changes the txid, causing INVALID_FORFEIT_TXS errors. The introspector already has arkade script info from the intent proof, so forfeits don't need Extension outputs. Also reverts the additionalOutputs parameter from buildForfeitTx since it's no longer needed.
CovVHTLC extends VHTLC with a 7th tapscript leaf that enables covenant-enforced claims. Anyone with the preimage can claim the VTXO — no user signature required. The Arkade introspector validates output constraints (destination address + amount) via introspection opcodes before co-signing. Includes: - CovVHTLC script class with 7 leaves (6 standard VHTLC + 1 covenant claim) - Covenant preimage condition with SIZE 32 check (matching Boltz Liquid design) - Arkade script using INSPECTOUTPUTSCRIPTPUBKEY + INSPECTOUTPUTVALUE - 24 unit tests covering construction, leaf accessors, script structure, validation - covclaim: standalone Node.js daemon that watches for on-chain covenant VTXOs and automatically builds + broadcasts claim transactions via the introspector
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
CovVHTLC + covclaim Daemon Review
TL;DR: Well-structured covenant claim extension. The script design is sound — SIZE 32 gate + HASH160 + introspector co-sign mirrors the proven Boltz Liquid pattern. A few security/robustness items worth addressing before this goes live.
Architecture ✅
The 7th leaf design is clean: ConditionMultisig with empty pubkeys + ArkadeVtxoScript.processScripts appending the tweaked introspector key = 1-of-1 multisig where the introspector validates output constraints before signing. Multi-input safety holds because the covenant pins output 0 to a fixed address + amount.
The batch.ts cleanup (removing addIntrospectorPacketToTx from commitment + forfeit txs) is correct — the introspector gets arkade scripts from intent proofs, so modifying those txs was both unnecessary and dangerous (changed txids).
Security Observations
1. Preimage over unauthenticated HTTP (covclaim/src/server.ts)
The REST API accepts preimages with zero auth. Anyone who can reach port 1234 can register arbitrary covenants. For regtest this is fine, but the README should explicitly warn that production deployments must be behind TLS + auth (or localhost-only). The preimage is the money — leaking it means anyone can front-run the claim.
2. Claiming unconfirmed UTXOs (covclaim/src/watcher.ts:53)
const utxo = utxos.find((u) => u.status.confirmed) ?? utxos[0];Claiming an unconfirmed UTXO is risky — if the funding tx gets reorged or RBF'd, the claim tx becomes invalid and the daemon marks the covenant "claimed" with a stale txid. Consider requiring at least 1 confirmation, or adding a re-check after broadcast.
3. No UTXO value validation (covclaim/src/claimer.ts)
If inputAmount < expectedAmount + fee, the tx construction will produce an invalid transaction (or negative change). Add an explicit check before building the tx:
if (inputAmount < expectedAmount + fee) {
throw new Error(`UTXO value ${inputAmount} insufficient for claim ${expectedAmount} + fee ${fee}`);
}4. Vsize underestimate (covclaim/src/claimer.ts:17)
ESTIMATED_VSIZE = 200 may be tight for deep taproot trees. A CovVHTLC with 7 leaves has a Merkle path depth of ~3, plus the witness includes sig (64b) + preimage (32b) + leaf script + control block. Worth measuring against a real regtest tx and adding margin, or computing dynamically.
Code Quality
5. Duplicated networkFromConfig — identical function in both covclaim/src/claimer.ts and covclaim/src/derive.ts. Extract to a shared util.
6. In-memory store (covclaim/src/store.ts) — daemon restart loses all registered covenants. Acceptable for alpha/regtest but worth a TODO comment or a simple JSON-file persistence option.
7. Test coverage is solid — 24 tests covering construction, leaf identity with VHTLC, arkade script introspection opcodes, validation edge cases, and address determinism. The test verifying first 6 leaves match VHTLC is particularly valuable for catching drift.
Cross-Repo Impact
- Bumps
introspectortov0.0.1-rc.1andarkdbranch tov0.9.0-rc.4in docker-compose + Dockerfiles — ensure these tags exist and are stable before merging. - The
CovVHTLCexport fromsrc/index.tsis a public API addition — consumers of@arkade-os/sdkwill see this in the next release. - Related: ArkLabsHQ/introspector must support the
IntrospectorPacketformat andINSPECTOUTPUTSCRIPTPUBKEY/INSPECTOUTPUTVALUEopcodes (PRs #9 and #11 per commit message).
Minor
covclaim/package.jsonpins@arkade-os/sdkasfile:..— works for monorepo dev but will need adjustment for standalone deployment or CI.- The
expressimport inserver.tsuses default import (import express from "express") — works withesModuleInterop: truebut worth noting for strict ESM consumers.
Summary
INSPECTOUTPUTSCRIPTPUBKEY+INSPECTOUTPUTVALUEbefore co-signing.SIZE 32 EQUALVERIFYbeforeHASH160check, matching Boltz's Liquid covenant claim design.Architecture
The covenant claim leaf uses
ConditionMultisigwith empty pubkeys —ArkadeVtxoScript.processScriptsappends the tweaked introspector key, resulting in a 1-of-1 multisig where only the introspector signs after validating the arkade script constraints.Multi-input spending is safe by design (same approach as Boltz on Liquid): the covenant pins output 0 to a specific address + amount, so additional inputs cannot redirect covenant funds.
Test plan
npx vitest run test/cov-vhtlc.test.ts)