Skip to main content

Back up and restore a wallet

Recovery from a phrase reconstructs your funds, not your records.

On Bitcoin, rescanning from a seed rebuilds your full transaction history, because the history is public and permanently associated with your keys. On Epic there is no public history to rebuild from. The chain holds blinded commitments with no sender, recipient or readable amount, so a rescan can identify which outputs are yours and nothing else about how they got there.

What to back up

ItemContainsPriority
Recovery phraseThe master secret, as wordsCritical. Losing it with no seed file loses the funds
wallet_data/wallet.seedThe same secret, encrypted with your passwordCritical, and useless to a thief without the password
wallet_data/db/sqlite/epic.dbTransaction history, account labels, slate messages, payment proof recordsImportant. Not recoverable from anywhere else
wallet_data/saved_txs/Stored transaction objectsImportant if you ever need repost
epic-wallet.tomlYour settingsConvenience. A fresh init regenerates defaults

Safe to lose: epic-wallet.log, wallet_tor/, .owner_api_secret, and the SQLite -wal and -shm files when the wallet is not running.

.api_secret must match the node's

The wallet's .owner_api_secret regenerates on next run. Its .api_secret is the credential the wallet presents to the node, so deleting it breaks node calls until the node's value is copied back in. See the credential the wallet presents to the node.

Backing up

The phrase is the only thing you strictly need, and it is printed once by init. To display it again:

epic-wallet recover

This prompts for your password, decrypts the seed and prints the phrase. It writes nothing and does not perform a recovery.

For a full backup, stop the wallet and copy the directory. Both commands below name the archive after the current date, and the restore section reuses the same name:

# Stop any listener or owner_api process first so SQLite is not mid-write.
stamp=$(date +%F)
tar czf "$HOME/epic-wallet-backup-$stamp.tar.gz" \
-C ~/.epic/main \
wallet_data epic-wallet.toml

# Verify the archive lists what you expect before trusting it.
tar tzf "$HOME/epic-wallet-backup-$stamp.tar.gz" | head

Keep the phrase and the archive in different places. The archive without the password is useless; the phrase alone is enough to move funds. Restore an archive into a scratch directory once before you need it, using the procedure in restoring a full directory backup.

Copy the database only while the wallet is stopped

SQLite runs in WAL mode. Copying epic.db while a wallet process is writing can produce an archive that restores to a corrupt database. Stop listen and owner_api first.

Restoring from a phrase

mkdir -p ~/restored
cd ~/restored
epic-wallet init -w -r

You will be prompted for the phrase, then for a new password. The phrase is validated on entry, so a mistyped word is rejected before the wallet is created.

-w puts the wallet in the current directory. It is a flag on init and takes no value, so epic-wallet -w . init is not valid. To point a later command at a wallet outside ~/.epic/<network>, either run it from that directory or pass --current_dir <path>.

Then rescan the chain to find your outputs:

epic-wallet scan
epic-wallet info

init -r marks the wallet as needing a scan, so this step is required rather than optional. Until it completes, the wallet does not know it owns anything.

Scanning takes a while and needs a synced node

The scan walks the chain testing outputs against your keys. It needs a node that is fully synced, and on mainnet it is not quick. -s starts it at a height instead of at 0:

epic-wallet scan -s <height>

Choose a height at or below the block that produced the wallet's first output. Any of these give one:

  • The confirmation_height of the earliest entry in epic-wallet txs on a device that still has the history.
  • The tip height at the time the wallet was created, from the block explorer.
  • A round number safely below either. Starting too low costs scan time; starting above the first output silently misses it and the balance comes back short.

With no -s the scan starts at 0, which is always correct and always the slowest.

What recovery does not bring back

Recovered by init -r plus scanNot recovered
All outputs belonging to your seedTransaction history, who you paid and when
Correct spendable balanceAccount labels, which are replaced by generated ones
The ability to spend everything you ownSlate messages attached to past transfers
Your epicbox, proof and Tor addressesPayment proof records for past transfers
Stored transaction objects, so repost will not work for old transfers
Any transfer that was in flight when you lost the wallet

Using the same recovery phrase on more than one device does not synchronize the wallets. Each instance derives the same keys and, after scanning against a synced node, identifies the same current outputs and calculates a valid balance. The transaction log is local database state, so each device records only the transfers it took part in, and one device can show the correct balance while missing transfers and status details recorded on the other. scan repairs output and balance state; it does not merge those records.

A recovery scan restores derivation paths, so outputs return to the account branch they were derived under. Labels do not survive: default keeps its name, and each other path found is labelled account_1, account_2 and so on in the order the scan discovers it (libwallet/src/internal/scan.rs:512). Rename by creating the labels you want, then moving the funds with the self transport:

epic-wallet account # list what the scan found, with each path
epic-wallet account -c savings
epic-wallet -a account_1 send -m self -d savings <amount>

See accounts.

In-flight transfers cannot be recovered

If a transfer was partly built when the wallet was lost, it is gone. The counterparty may still hold a slate referencing outputs you now own, but your side has no record of the exchange and the reserved-output state was in the lost database.

After a recovery scan those outputs appear spendable again. If the counterparty later submits a finalised transaction built from them, whichever transaction confirms first wins and the other becomes invalid. Agree with the counterparty which attempt is live before resending. See interactive transactions.

Restoring a full directory backup

If you kept the whole wallet_data directory, restore that instead of recovering from the phrase. It brings back history, labels and proof records as well as funds. Substitute the archive you actually made in backing up; the date in the filename is the day it was created.

stamp=2026-08-22 # the date on the archive you are restoring
mkdir -p ~/.epic/main
tar xzf "$HOME/epic-wallet-backup-$stamp.tar.gz" -C ~/.epic/main
epic-wallet info

If the figures disagree with the chain afterwards, run epic-wallet scan to rebuild output state. That leaves your history intact.

Recovering into a directory that already has a wallet

The CLI will not do it. init -r still goes through wallet creation, which refuses when a seed file is present (impls/src/lifecycle/default.rs:188), and there is no override flag.

Move the existing wallet aside first:

mv ~/.epic/main/wallet_data/wallet.seed ~/.epic/main/wallet_data/wallet.seed.old
epic-wallet init -r
Never run init without -r to "reset" a wallet

init on its own generates a brand-new seed. If you delete wallet_data/ but keep epic-wallet.toml, init proceeds and you end up with an empty wallet holding none of your funds. They are then reachable only from the phrase.

Changing your password

epic-wallet change_password

The seed is re-encrypted with the new password. The phrase does not change, so an old backup of the phrase remains valid.

change_password writes wallet.seed.bak before re-encrypting, then deletes it once the new password is confirmed. Passing --remove-backup keeps the file instead (src/cmd/wallet_args.rs:452). Delete a kept backup once you have confirmed the new password works.

scan --delete_unconfirmed is destructive

Plain scan rebuilds. Adding -d deletes unconfirmed outputs, unlocks locked outputs, and deletes the transaction log entries associated with them.

The case for it is a wallet holding reserved outputs whose transfers are dead and which cancel cannot clear. It removes history. Try cancelling individual transfers first.

Next