Covenant claim watcher daemon for Arkade VHTLCs. Watches for on-chain UTXOs at registered CovVHTLC taproot addresses and automatically claims them via the introspector-enforced covenant path.
Inspired by BoltzExchange/covclaim (Liquid), but for Arkade on Bitcoin using the introspector co-signing service.
- A client registers a covenant-claimable VTXO via
POST /covenantwith the VHTLC parameters and the preimage - The daemon derives the
CovVHTLCtaproot address and starts polling esplora for UTXOs at that address - When a UTXO appears (after unilateral exit or round expiry puts the VTXO on-chain), the daemon:
- Builds a transaction spending via the
covenantClaimleaf - Submits the PSBT to the introspector for co-signing (the introspector validates output constraints match the arkade script)
- Broadcasts the signed transaction via esplora
- Builds a transaction spending via the
- Node.js 22+
- An introspector instance
- An esplora instance
- An Ark server (
arkd) for the network you're targeting
Via environment variables:
| Variable | Default | Description |
|---|---|---|
ESPLORA_URL |
http://localhost:3000 |
Esplora REST API URL |
INTROSPECTOR_URL |
http://localhost:7073 |
Introspector REST API URL |
PORT |
1234 |
HTTP server port |
POLL_INTERVAL_MS |
5000 |
Esplora polling interval in ms |
NETWORK |
regtest |
Bitcoin network (regtest, signet, mainnet) |
cd covclaim
npm install
npm run devcd covclaim
npm install
npm run build
npm startdocker build -t covclaim -f covclaim/Dockerfile .
docker run -p 1234:1234 \
-e ESPLORA_URL=http://esplora:3000 \
-e INTROSPECTOR_URL=http://introspector:7073 \
-e NETWORK=regtest \
covclaimRegister a VTXO to watch for covenant claiming.
Request:
{
"sender": "<hex x-only pubkey>",
"receiver": "<hex x-only pubkey>",
"server": "<hex x-only pubkey>",
"preimage": "<hex 32-byte preimage>",
"claimAddress": "<bech32/bech32m address>",
"expectedAmount": 10000,
"refundLocktime": 800100,
"unilateralClaimDelay": { "type": "blocks", "value": 100 },
"unilateralRefundDelay": { "type": "blocks", "value": 102 },
"unilateralRefundWithoutReceiverDelay": { "type": "blocks", "value": 103 }
}Response (201):
{
"id": "uuid",
"taprootAddress": "bcrt1p...",
"status": "watching"
}Check status of a registered covenant.
Response:
{
"id": "uuid",
"taprootAddress": "bcrt1p...",
"status": "watching|claiming|claimed|failed",
"utxo": { "txid": "...", "vout": 0, "value": 10546 },
"claimTxid": "...",
"error": null,
"createdAt": 1711900000000
}Returns { "status": "ok" }.
- Start
arkd, introspector, and esplora (e.g., via docker-compose from the Ark repo) - Start the daemon:
ESPLORA_URL=http://localhost:3000 \
INTROSPECTOR_URL=http://localhost:7073 \
NETWORK=regtest \
npm run dev- Create a
CovVHTLCin your wallet, perform a unilateral exit to put the VTXO on-chain - Register the covenant with the daemon:
curl -X POST http://localhost:1234/covenant \
-H 'Content-Type: application/json' \
-d '{
"sender": "...",
"receiver": "...",
"server": "...",
"preimage": "...",
"claimAddress": "bcrt1q...",
"expectedAmount": 10000,
"refundLocktime": 800100,
"unilateralClaimDelay": { "type": "blocks", "value": 100 },
"unilateralRefundDelay": { "type": "blocks", "value": 102 },
"unilateralRefundWithoutReceiverDelay": { "type": "blocks", "value": 103 }
}'- The daemon will detect the UTXO and claim it automatically.