Reference / CLI commands
genesis wallet
Use genesis wallet to manage a local encrypted wallet and expose a stable
machine-readable interface for agents.
Supported chains:
btc: local BIP39/BIP84-derived Bitcoin address, Esplora balance/UTXO/broadcastevm: local BIP39-derived EVM addresses through EVM JSON-RPC URLs. Ethereum, Base, and Monad are enabled by default with public RPC endpoints.sol: local BIP39/SLIP-0010-derived Solana address through@solana/web3.jstrx: local BIP39-derived TRON address through TronWebxmr: read and transfer throughmonero-wallet-rpc; Genesis does not sign Monero locallylndhub: read and pay Lightning invoices through an external LndHub-compatible REST API (e.g. BlueWallet); Genesis does not hold Lightning keys locally
Security model:
- The encrypted keystore is stored under the Genesis credentials directory with owner-only file permissions.
- Public address metadata is readable while the keystore is locked.
- One BIP39 secret recovery phrase derives every local keystore chain account
(
btc,evm,sol, andtrx) through that chain's configured derivation path. EVM accounts share the same derived address across configured EVM networks. - Existing mnemonics, private keys, passphrases, and raw secret material are not returned by JSON output, Gateway RPC, or the Control UI.
- EVM message, digest, and raw transaction signing are CLI-only and return signatures or signed transaction bytes, never private keys.
- The Control UI can create a new recovery phrase or import/replace one through
the admin-scoped
wallet.recoveryPhrase.setmethod. A newly generated phrase is returned once so it can be backed up; imported or existing phrases are not echoed back. - Send and broadcast flows stay in the CLI.
Create or import
Create a new wallet:
printf '%s\n' "$GENESIS_WALLET_PASSPHRASE" | genesis wallet init --passphrase-stdin
Import a mnemonic:
export GENESIS_WALLET_PASSPHRASE='use-a-long-local-passphrase'
printf '%s\n' "$MNEMONIC" | genesis wallet import --mnemonic-stdin
Notes:
initgenerates a new mnemonic and encrypts it locally.--show-mnemonicprints a generated mnemonic once in human-readable output and cannot be combined with--json.import --mnemonic-stdinreads the mnemonic from stdin and reads the passphrase fromGENESIS_WALLET_PASSPHRASE.--overwritereplaces an existing keystore.
Addresses and balances
Public addresses:
genesis wallet
genesis wallet list
genesis wallet address --chain evm
genesis wallet address --json
Native balances:
genesis wallet balance --chain btc
genesis wallet balance --chain evm --account evm:base --json
Configured EVM tokens and NFT collections:
genesis wallet tokens --account evm:ethereum --json
genesis wallet nfts --account evm:base --json
Token and NFT commands read the contracts configured under
wallet.networks.evm.chains.<chain>.tokens and
wallet.networks.evm.chains.<chain>.nfts. ERC-20 token balances use
balanceOf; token metadata comes from config or from symbol, name, and
decimals contract calls. ERC-721 collections can show balanceOf and can
check configured tokenIds through ownerOf/tokenURI. ERC-1155 collections
use configured tokenIds and balanceOf(address, tokenId).
Agents should prefer --json and treat the response as the stable automation
surface.
Quote and send
Quote a native asset transfer:
genesis wallet quote --chain sol --to <address> --amount 0.1
genesis wallet quote --chain sol --to <address> --amount 0.1 --json
Broadcasting is intentionally harder. A send must pass all configured and per-invocation guards:
wallet.spending.enabled: true--yes- wallet passphrase from
GENESIS_WALLET_PASSPHRASEor--passphrase-stdin, or--empty-passphrasefor a keystore created without one GENESIS_WALLET_ALLOW_SPEND=1unlesswallet.spending.requireAllowEnvis disabledwallet.spending.maxNativeAmount, when configured
Example:
GENESIS_WALLET_ALLOW_SPEND=1 \
GENESIS_WALLET_PASSPHRASE='use-a-long-local-passphrase' \
genesis wallet send --chain trx --to <address> --amount 1 --yes
Signing and raw transactions
The wallet can sign EVM payloads with a configured EVM account:
GENESIS_WALLET_PASSPHRASE='use-a-long-local-passphrase' \
genesis wallet sign-message --chain evm --account evm:base --message 'hello' --yes --json
GENESIS_WALLET_PASSPHRASE='use-a-long-local-passphrase' \
genesis wallet sign-digest --chain evm --digest 0x0000000000000000000000000000000000000000000000000000000000000001 --yes --json
sign-message uses the EVM personal-sign/EIP-191 message prefix. Use
--message-hex to sign exact message bytes. sign-digest signs the exact
32-byte digest and does not add a message prefix.
Raw transaction signing and broadcast use the same spending gates as send
because they can move funds or invoke contracts:
GENESIS_WALLET_ALLOW_SPEND=1 \
GENESIS_WALLET_PASSPHRASE='use-a-long-local-passphrase' \
genesis wallet sign-raw-transaction \
--chain evm \
--account evm:base \
--tx-json '{"to":"0x0000000000000000000000000000000000000001","nonce":0,"gasLimit":"21000","gasPrice":"1","value":"1"}' \
--yes \
--json
GENESIS_WALLET_ALLOW_SPEND=1 \
GENESIS_WALLET_PASSPHRASE='use-a-long-local-passphrase' \
genesis wallet broadcast-raw \
--chain evm \
--account evm:base \
--raw-transaction 0x... \
--yes \
--json
sign-raw-transaction accepts unsigned EVM transaction request fields such as
to, from, nonce, gasLimit or gas, gasPrice, maxFeePerGas,
maxPriorityFeePerGas, value, data, chainId, type, and accessList.
If chainId is omitted, Genesis fills the selected EVM network's chain id.
If chainId is present, it must match the selected account's network.
When transaction.value is present, wallet.spending.maxNativeAmount is
checked against that native asset value. Genesis does not decode arbitrary
contract calldata for token-level spend limits.
Configuration
Minimal example:
{
wallet: {
enabled: true,
networks: {
btc: { network: "mainnet" },
evm: {
// Optional. Omit `rpcUrl` to use the built-in public RPC defaults for
// ethereum, base, and monad. Override or disable individual EVM chains
// under `chains`.
chains: {
ethereum: {
rpcUrl: { source: "env", provider: "default", id: "ETH_RPC_URL" },
tokens: {
usdc: {
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
symbol: "USDC",
name: "USD Coin",
decimals: 6,
},
},
nfts: {
badge: {
address: "0x0000000000000000000000000000000000000001",
standard: "erc721",
tokenIds: ["1"],
},
},
},
base: {
rpcUrl: { source: "env", provider: "default", id: "BASE_RPC_URL" },
},
monad: {
rpcUrl: { source: "env", provider: "default", id: "MONAD_RPC_URL" },
},
},
},
sol: { network: "mainnet-beta" },
trx: {
fullHost: "https://api.trongrid.io",
apiKey: { source: "env", provider: "default", id: "TRONGRID_API_KEY" },
},
xmr: {
walletRpcUrl: "http://127.0.0.1:18082/json_rpc",
username: { source: "env", provider: "default", id: "MONERO_RPC_USER" },
password: { source: "env", provider: "default", id: "MONERO_RPC_PASSWORD" },
},
},
spending: {
enabled: false,
requireAllowEnv: true,
maxNativeAmount: "0.1",
},
},
}
Secret-bearing wallet fields support SecretRef inputs where the config schema marks them sensitive. See Secrets Management.
When wallet.networks.evm.rpcUrl is omitted and no legacy single-chain EVM
config is set, Genesis creates EVM accounts for evm:ethereum, evm:base, and
evm:monad. A legacy single-chain config for Ethereum, Base, or Monad also uses
that chain's public RPC when rpcUrl is omitted. These defaults are
rate-limited and are best for setup, address display, and low-volume balance
checks. For production or agentic send flows, configure private or secret-backed
endpoints under wallet.networks.evm.chains.
Browser web3 provider
With wallet.browser.enabled: true, every page the agent opens with the
browser tool gets an injected web3 wallet named Genesis:
- EVM:
window.ethereum(EIP-1193) and an EIP-6963 announcement. Chains are the enabledwallet.networks.evmnetworks;wallet_switchEthereumChainonly switches between them. Read-only JSON-RPC (eth_call,eth_estimateGas, ...) goes to the configured RPC URL. - Solana: a Wallet Standard wallet plus
window.solana, using the configuredwallet.networks.solcluster.
Account and chain queries answer immediately. personal_sign,
eth_signTypedData_v4, eth_sendTransaction, and Solana signMessage,
signTransaction, signAllTransactions, and signAndSendTransaction wait in an
approval queue. The agent sees them through the owner-only wallet tool
(pending, then approve or reject); unanswered requests are rejected after
five minutes. Transaction signing also requires wallet.spending.enabled: true,
and eth_sendTransaction values must fit wallet.spending.maxNativeAmount.
Signing needs the keystore unlocked in the running gateway:
GENESIS_WALLET_PASSPHRASE=... genesis wallet unlock --ttl 30
genesis wallet unlock --empty-passphrase # keystore created without a passphrase
genesis wallet lock
The Control UI Wallet tab has the same controls in its Signing Session card
(passphrase, 15 minutes to 24 hours, Lock now). Both call the admin-scoped
wallet.unlock / wallet.lock gateway methods.
The mnemonic stays in gateway memory only until the TTL (default 15 minutes,
max 24 hours) expires, genesis wallet lock runs, or the gateway restarts.
{
wallet: {
browser: {
enabled: true,
// Optional: only these origins see the provider.
allowedOrigins: ["https://app.uniswap.org", "https://jup.ag"],
},
spending: { enabled: true, maxNativeAmount: "0.05" },
},
}
Notes:
- Any page JavaScript on an allowed origin can raise signing requests and read
the wallet addresses. Prefer
allowedOrigins, and keep in mind that the agent decides approvals. - Tabs that were already open when the browser connected pick up the provider on their next navigation or reload.
- Managed and remote CDP profiles inject through a Playwright binding on every page load.
existing-sessionprofiles (Chrome DevTools MCP) get the provider as anavigate_pageinit script on each browser-tool navigation, talking to a token-protected loopback bridge (http://127.0.0.1:<random port>). Full page reloads the dApp triggers itself drop it until the next browser-tool navigation. Chrome may ask to allow local network access the first time a site uses the bridge, and a strict pageconnect-srcCSP blocks it (requests then fail with code 4900).- Browsers on a paired node host forward provider requests to the gateway over
the node connection (
node.wallet.web3), so they use the gateway'swallet.browserconfig, unlocked session, and approval queue. The node's own wallet config is ignored.
Gateway and Control UI
The Gateway exposes read-only wallet.summary for operator clients with
operator.read. The Control UI Wallet tab calls that method and displays public
addresses, balance refresh results, warnings, and copy buttons.
The Control UI also supports admin-scoped recovery phrase management through
wallet.recoveryPhrase.set:
mode: "generate"creates a new BIP39 phrase, encrypts it locally, derives all local chain accounts, and returns the generated phrase once.mode: "import"imports a BIP39 phrase, encrypts it locally, derives all local chain accounts, and does not return the phrase.passphraseis optional for the web/admin method; omit it to create or import a wallet without a passphrase.overwrite: trueis required when replacing an existing keystore.
No Gateway or web method returns existing seed phrases, private keys, stored passphrases, signatures, raw transaction signing, or a send/broadcast control.