Skip to main content

Wallet operations

What to do with a wallet that is set up and pointed at a node. Everything here is mainnet, so there is no network flag, and every command that moves value is real.

Set up first: node and wallet setup. The transfer mechanics are the ones you already ran on the local chain in your first transfer.

Read what the wallet knows

epic-wallet info
Total 15.00000000
Immature Coinbase 0.00000000
Awaiting Confirmation 0.00000000
Locked by transaction 0.00000000
Currently Spendable 15.00000000

Amounts print with 8 decimals, because 1 EPIC is 100,000,000 freemans. Rows at zero are sometimes suppressed rather than shown.

A gap between Total and Currently Spendable is normal and means one of three things. Coinbase maturity has not passed, a transfer is in flight and has reserved inputs, or the confirmation threshold has not been met. Outputs and locking explains which is which.

--min_conf sets that confirmation threshold, the minimum depth an output needs before the wallet will treat it as spendable. It defaults to 10 and is declared on exactly three subcommands, send (src/cmd/wallet_args.rs:143), pay (src/cmd/wallet_args.rs:263) and info (src/cmd/wallet_args.rs:361). There is no configuration key, so the default applies unless you pass the flag. On info it changes the Currently Spendable figure the summary reports, which is how you check what a given threshold would make available:

epic-wallet info --min_conf 1

Coinbase maturity is a separate, consensus-level floor and is not affected by this flag. See emission timing.

epic-wallet txs

Per-transaction detail. Sent (Created) with Confirmed? false is an incomplete transfer holding reserved inputs. The From/To Address column is populated only for epicbox transfers; file and HTTP leave it empty, so the log alone cannot tell you who paid you.

Confirmation depth of a transaction

A transaction's depth is the current chain height minus the height at which the wallet saw it confirm. The wallet records that height in the transaction log as confirmation_height (libwallet/src/types.rs:849), set when the refresh finds the outputs on the chain (libwallet/src/internal/updater.rs:370). It is null until confirmed is true. The chain height comes from the node's get_status, field tip.height.

Both fields are on the Owner API's retrieve_txs result. epic-wallet txs prints the height in its output rather than the depth, so an integration computes the subtraction itself.

Automating these commands

epic-wallet prompts for the wallet password when a command needs one. Two ways to supply it without a prompt:

On the command line. -p is a global flag, so it goes before the subcommand (src/cmd/wallet_args.rs:78). Read it from the environment rather than typing it, so the value stays out of shell history:

epic-wallet -p "$EPIC_WALLET_PASSWORD" info

Through the Owner API. open_wallet takes the password as a parameter and returns a session token for every later call. The example clients read EPIC_WALLET_PASSWORD from the environment and pass it straight to open_wallet, which is the pattern to copy:

wallet = EpicWallet()
wallet.open_wallet(password=os.environ["EPIC_WALLET_PASSWORD"])

Receive

Someone paying you needs your wallet to take part, because an Epic transfer is built by both sides. That means a listener, or a slate file you process by hand.

epic-wallet listen -m epicbox -n

This holds a connection to an epicbox relay. Print the address to give out:

epic-wallet address

The epicbox address is 52 base58 characters, @, then the relay domain. It routes slates to you. It is not an on-chain account, it cannot be looked up in the chain, and it does not reveal your balance. A corrupted address fails its checksum locally before anything is sent.

A slate sent while you were offline is delivered when you reconnect. Two separate limits bound how long the relay holds one, and the shorter is not the storage expiry, so a sender whose transfer never lands cancels and retries rather than waiting indefinitely. See delivery and its limits.

To process a slate file instead of listening:

epic-wallet receive -m file -i slate.tx
# writes slate.tx.response, which goes back to the sender

Send

epic-wallet send -m epicbox -d <recipient-address> <amount>

Can spend funds This reserves your inputs immediately, before the recipient has done anything. See what reserves outputs.

Quote the fee before committing to it:

epic-wallet send -e -m epicbox -d <recipient-address> <amount>

-e/--estimate-selection prints the amount and fee for both selection strategies and builds nothing (controller/src/command.rs:482).

Fees follow the number of inputs and outputs rather than a flat rate, and the arithmetic is in keep more than one spendable output.

After posting, the command polls the node's mempool to confirm the transaction arrived; see the send appears to hang. With -m epicbox both sides need a subscription, because the countersigned slate returns through the relay and your own listener finalises it.

Epicbox uses slate V2 and cannot carry a payment proof. See transports.

Keep more than one spendable output

A wallet holding a single output can run one transfer at a time. The send locks that output and writes the change as unconfirmed, so nothing is spendable until the transfer confirms and the change reaches --min_conf confirmations. See what reserves outputs.

Split the balance by sending to yourself. -m self locks the inputs and receives the slate back into the same wallet in one command (controller/src/command.rs:550), -d names the destination account, and -o sets how many change outputs it writes:

epic-wallet send -m self -d default -o 3 10

Can spend funds The self-send locks the selected inputs until it confirms.

That transaction has one input, four outputs and one kernel: 10 EPIC paid back to the default account plus three change outputs. Once it confirms, four transfers can be in flight at once.

What an output costs

The fee is the transaction's weight times 0.001 EPIC. Weight counts each output four times, each kernel once, subtracts each input, and has a floor of 1 (weight(), tx_fee()):

weight = max(4 × outputs + kernels − inputs, 1)
TransactionInputsOutputsWeightFee
Send with one change output1280.008
Self-send with three change outputs14160.016
Self-send with seven change outputs18320.032
Send consolidating ten outputs10210.001

Each additional output adds 0.004 EPIC. Each additional input removes 0.001, down to the floor.

Which outputs a send spends

-s/--selectionSelectsResult
smallest, the defaultthe fewest outputs that cover the amount and the feethe rest of the balance stays spendable
allevery output with at least --min_conf confirmationsthe whole spendable balance is locked for the transfer, the fee is lower, and one change output comes back

all returns a single change output, so the wallet is again holding one output. It links the spent outputs to each other on chain; see InitTxArgs.

Repost a completed transfer that never confirmed

A finalised transaction is written to wallet_data/saved_txs/ before it is posted, so it can be posted again without rebuilding it. That is the case when the transfer completed both rounds but the post did not reach the node.

epic-wallet txs # find the id of the unconfirmed Sent entry
epic-wallet repost -i <id>
FlagEffect
-i <id>The transaction log id holding the stored transaction
-m <file>Write the transaction to that file instead of posting it
-fPost directly, bypassing Dandelion relay

Declared at src/cmd/wallet_args.rs:335. repost needs the stored transaction object, so it works only for transfers whose saved_txs/ entry is still present. A wallet recovered from a phrase alone has none.

Cancel a transfer that cannot complete

Destructive Cancelling releases the reserved inputs and abandons the transfer.

epic-wallet txs # find the id of the incomplete transfer
epic-wallet cancel -i <id>

See cancelling has preconditions, and diagnose a stuck transaction for what to do when cancel refuses.

Repair a wallet that disagrees with the chain

epic-wallet scan

Rescans the chain against your keys and rebuilds the local view of your outputs.

It does not release locked outputs, because a lock is a local record the chain knows nothing about. See what releases them.

scan --delete_unconfirmed is a different thing

It unlocks locked outputs and deletes their transaction log entries, so it discards records rather than rebuilding them. Reach for plain scan first.

Accounts

An account is a label bound to one derivation path inside the wallet's single seed. Every wallet has one named default.

epic-wallet account # list every label with its derivation path
epic-wallet account -c savings # create one
epic-wallet -a savings info # run any command against it

-a goes before the subcommand and defaults to default. It selects the account for that one invocation, and it sets which account a send spends from and which one a receive or an epicbox listener credits.

Accounts share the recovery phrase, the password and the backup, so they back up together. See accounts for the derivation scheme and what each account holds separately.

Change the password

epic-wallet change_password

The seed is re-encrypted with the new password and the phrase does not change. wallet.seed.bak is written and then deleted; pass --remove-backup to keep it. See changing your password.

Next