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)
| Transaction | Inputs | Outputs | Weight | Fee |
|---|---|---|---|---|
| Send with one change output | 1 | 2 | 8 | 0.008 |
| Self-send with three change outputs | 1 | 4 | 16 | 0.016 |
| Self-send with seven change outputs | 1 | 8 | 32 | 0.032 |
| Send consolidating ten outputs | 10 | 2 | 1 | 0.001 |
Each additional output adds 0.004 EPIC. Each additional input removes 0.001, down to the floor.
Which outputs a send spends
-s/--selection | Selects | Result |
|---|---|---|
smallest, the default | the fewest outputs that cover the amount and the fee | the rest of the balance stays spendable |
all | every output with at least --min_conf confirmations | the 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>
| Flag | Effect |
|---|---|
-i <id> | The transaction log id holding the stored transaction |
-m <file> | Write the transaction to that file instead of posting it |
-f | Post 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 thingIt 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.