This repository is the recovery-only public source package for Kaspa Forge. It lets users recover funds from an existing Kaspa Safe, Escrow or Deposit without the Kaspa Forge website, hosted API or operator infrastructure.
It intentionally contains only:
contracts/— the publishedvault.silandescrow.silcovenant sources;vaultctl/— the standalone Safe recovery CLI;recovery-kit/— the Escrow and Deposit transaction core,dealctl, schemas, test vectors, EN/RU guides and self-contained offline.agedecryptor;SECURITY.md— coordinated disclosure policy;ERRATA.md,TOOLING.mdandAUDITS/— known contract limitations, exact build boundary and dated internal review records;RECOVERY-SHA256SUMS— checksums for the root recovery boundary. The Deal Recovery Kit also has its complete package manifest atrecovery-kit/RECOVERY-SHA256SUMS.
The website, blog, Desk/application source, Boards indexer, server, image storage, NSFW model, reports, Telegram integration, operator/admin APIs, deployment configuration, infrastructure and secrets are outside this repository by design.
- Use Code → Download ZIP and store the ZIP with your encrypted Desk
.agebackup. Do not wait for an emergency. - Verify
RECOVERY-SHA256SUMS. - With networking disabled, open
recovery-kit/keyfile-decrypt.htmlfrom disk and rehearse with a test/exported.agebackup. - Delete the decrypted JSON after the rehearsal. It contains private keys.
The key file is standard passphrase-encrypted age data. Technical users may also decrypt it with:
age -d kaspa-office-profile.age > profile.jsonNever upload the .age file or decrypted JSON to an online decryptor, and never send either one,
your password or a private key to support.
Prerequisites: Rust, protobuf-compiler, and clang.
# Debian/Ubuntu
sudo apt install -y protobuf-compiler clang
cd vaultctl
cargo build --release --locked
./target/release/vaultctl status --recovery ../vault.jsonvaultctl defaults to grpc://node.kaspaforge.org:16110. For independence from that public
front, run any compatible Kaspa v2+ node with --utxoindex and pass
--node grpc://YOUR_NODE:16110.
The build pins SilverScript to commit
26e3b9f94821b6fe47a2492755252ec4f995abb1; Cargo.lock is part of the export. The contract source
hashes and compiler/address verification procedure are in TOOLING.md.
Decrypt the Desk backup on a disconnected computer, then select the record whose vault_addr
matches the vault:
jq -r '.vaults[] | .vault_addr' profile.json
jq '.vaults[] | select(.vault_addr == "kaspa:YOUR_VAULT_ADDRESS")' profile.json > vault.json
chmod 600 profile.json vault.jsonAn .age export from the Safe creation device includes alarm_sk only when shared alarm-key
storage was selected. Forge Sync deliberately does not transfer alarm keys. If the alarm key was
kept separately, add it as alarm_sk before cancel or migrate. Keep hot and alarm keys apart:
together they can move the entire vault immediately.
| command | purpose | required secret |
|---|---|---|
status --recovery vault.json [--dest <addr>] |
show balance, age and timers | none |
initiate --recovery vault.json --to <kaspa:q…> |
start a delayed withdrawal | hot key |
cancel --recovery vault.json --dest <kaspa:q…> |
cancel an in-flight withdrawal | alarm key |
complete --recovery vault.json --dest <kaspa:q…> |
deliver a matured withdrawal | none |
checkin --recovery vault.json |
reset the inheritance timer | hot key |
inherit --recovery vault.json [--heir-sk <hex>] |
claim after the inheritance period | none / heir key |
migrate --recovery vault.json --to <kaspa:q…> [--dest <addr>] |
immediate full migration | hot + alarm keys |
Use --dry-run before broadcasting. For cancel, complete, or an in-flight migrate, --dest
is the fixed withdrawal destination, not the vault address.
Every covenant UTXO has its own age and timer. status lists all of them. When several matching
UTXOs exist, mutating commands refuse to guess: select one with --outpoint <txid:index> or use
--all. --all creates one independent single-input transaction per UTXO and stops on the first
rejection; it never combines UTXOs. Read TOOLING.md before using batch mode.
Run the covenant self-test:
cd vaultctl
cargo run --release --locked -- selftestcontracts/escrow.sil backs both Kaspa Escrow and Kaspa Deposit. A Deposit maps the holder to the
contract buyer and the depositor to the contract seller. Every permitted path constrains funds to
the buyer, seller, their split, or the fixed service-fee address:
release/refund— amicable outcomes;autoRelease— seller payout after the dispute window;dispute— freezes optimistic auto-release;arbitrateToBuyer,arbitrateToSeller,arbitrateSplit— constrained arbiter outcomes;timeoutToBuyer,timeoutToSeller— emergency exits after the arbiter deadline.
Build dealctl from the recovery-kit root:
cd recovery-kit
sha256sum -c RECOVERY-SHA256SUMS
cargo build --release --locked -p dealctl
./target/release/dealctl --helpRead the complete guides before using it:
recovery-kit/recovery/README.md— English;recovery-kit/recovery/README.ru.md— Russian.
The safe air-gapped boundary is:
- Offline: decrypt,
extract,verify, then create a publicwatch.json. - Online: use
status --watchandprepare --watchto createlines.json. - Offline: sign the line package against the private recovery record.
- Online: submit the signed transaction.
Only watch.json, lines.json and the signed transaction cross to the online host. The .age
backup, decrypted profile, recovery record and private key remain offline. Offline signing rejects
a line package whose network, product or deal ID does not match the recovery record.
- Keys originate client-side and are encrypted in the Desk
.agebackup. - Forge Sync is not a replacement for a fresh full
.ageexport or a separate Safe alarm card. vaultctlanddealctlrecompute covenant identities and fail closed on mismatches.- A service capability token is not needed for on-chain recovery.
- Build from reviewed source and verify the checksum manifests; do not trust cached or third-party binaries.
- Lost passwords and lost private keys cannot be recovered by Kaspa Forge.
Known limitations of the immutable contract versions, including bounded output-count slack and the
per-UTXO timer model, are disclosed in ERRATA.md. Security reports should follow
SECURITY.md.
Delete plaintext recovery material when finished:
rm -f profile.json vault.json deal-recovery.json