Skip to main content

Multi-Chain Embedded Wallets

Each embedded-wallet user gets native treasury wallets — one keypair per chain family, stored in the org's __treasury-keys vault. Keys are generated inside HSM-backed infrastructure; private material is never returned except through explicit export with re-authentication.

Human-only

Treasury wallet APIs enforce require_human(). Agents always receive 403. Autonomous signing uses agent signing keys, not treasury wallets.

Supported chains

ChainCurveAddress exampleNotes
Ethereumsecp256k10x4e83… (EIP-55)EIP-1559, ERC-20, ERC-4337 gasless
Bitcoinsecp256k1bc1q… (bech32)UTXO model, fee rate in sat/vB
SolanaEd255197xKX… (base58)SPL tokens, memo program
XRPEd25519rN7d…30+ tx types via xrpl_tx_json
CardanoEd25519addr1…Native multi-asset, min-ADA
Tronsecp256k1T9yD…TRC-20, energy limits

EVM network names in API requests (e.g. base, optimism, polygon) map to the canonical ethereum signing key chain for address derivation where applicable. Configure RPC URLs in the chain registry for broadcast and balance queries.

Key storage

Private keys live at:

__treasury-keys/users/{user_id}/chains/{chain}/private_key

The __treasury-keys vault:

  • Does not count toward vault/secret quotas
  • Is hidden from GET /v1/vaults and Shroud's secrets manifest
  • Blocks direct secret reads — use export endpoint or signing APIs only

MPC custody is auto-configured by billing tier when the vault is created:

TierModeMeaning
Pro / TeamXOR 2-of-2 client custodyServer share + optional client share on read
Business / EnterpriseShamir 2-of-3 multi-HSMGCP + AWS + Azure KMS shares

See Advanced — custody tiers.

Wallet quota

Treasury wallets count toward org wallet quota:

TierWallets
Free10
Pro10,000
Team250,000
Business1,000,000
EnterpriseUnlimited

Platform org admins bypass limits via effective_billing_tier_for_limits.

Provisioning wallets

On first login (embedded flows)

Pass auto_provision_chains to Email OTP verify or social login:

await client.auth.verifyEmailOtp({
email: "user@example.com",
code: "123456",
auto_provision_chains: ["ethereum", "solana", "bitcoin"],
});

The React widget provisions chains from its chains prop on first successful login.

Explicit generation (authenticated user)

const { data } = await client.treasuryWallets.generateWallets({
chains: ["ethereum", "solana"], // omit for all six
});

for (const w of data.wallets) {
console.log(w.chain, w.address, w.curve);
}

Chains where the user already has an active wallet are skipped silently.

Listing wallets

const { data } = await client.treasuryWallets.listWallets();
// data.wallets[] — id, chain, address, curve, is_active
curl "https://api.1claw.xyz/v1/treasury/wallets" \
-H "Authorization: Bearer $USER_JWT"

Balances

Query native + optional ERC-20/SPL/TRC-20 token balances:

const { data } = await client.treasuryWallets.getWalletBalance("ethereum", [
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // Base USDC
]);

console.log(data.native_balance, data.native_symbol);
console.log(data.tokens);
curl "https://api.1claw.xyz/v1/treasury/wallets/ethereum/balance?tokens=0x833589..." \
-H "Authorization: Bearer $USER_JWT"

The React widget refreshes balances every 30 seconds.

Import, export, rotate

OperationEndpointRe-auth
Import (BYOK)POST .../importX-Auth-Confirm (password)
Export private keyPOST .../exportX-Auth-Confirm (password)
Rotate keypairPOST .../rotateSession JWT
DeactivateDELETE .../{chain}Session JWT
await client.treasuryWallets.exportWallet("ethereum", userPassword);

Export and failed re-auth attempts are audit-logged (treasury_wallet.export). Failed password attempts count toward account lockout.

Export policy

Exporting keys to end-user devices increases custody risk. Prefer keeping signing server-side and using spend policies instead of raw key export for most embedded apps.

Embedded wallets vs EVM L2s

Marketing and product copy often list "Ethereum + L2s" (Base, Optimism, Arbitrum, Polygon). On-chain sends specify the target chain by name in the send request; the underlying treasury key for EVM chains is the user's ethereum chain wallet unless you import chain-specific keys.

Configure L2 RPC URLs in the chain registry so broadcasts and balance checks resolve correctly.