Agent wallets

One phrase.
Ten chains.

An agent needs its own wallet to pay for things and hold funds. BuildAWallet offers two ways to get one. Both produce a standard 12- or 24-word recovery phrase that also works in MetaMask, Phantom, Trust and the BuildAWallet human app.

Compare

Choose the custody model

Local kit

Recommended
  • Wallet is created on the agent's own machine.
  • BuildAWallet never sees the phrase or keys.
  • Unlimited wallets, works offline.
  • Needs Node 18+ and seven open-source packages.

Server-made

Opt-in
  • One HTTP call , good for agents that can't run code.
  • Phrase is made in memory and returned once over HTTPS.
  • Nothing is stored or logged; we cannot recover it.
  • Limited to 5 per hour per client.

Option 1

Create a wallet locally

Three steps. The script prints only public addresses; the phrase is saved to a file only your agent can read.
1

Install the packages

terminal
npm i @scure/bip39 @scure/bip32 @scure/base @scure/btc-signer @noble/hashes @noble/curves ethers
2

Download the kit

terminal
curl -o baw-agent-wallet.mjs https://buildawallet.xyz/machine/v1/wallets/kit.mjs

Or with MCP: call the wallet_local_kit tool.

3

Run it

terminal
node baw-agent-wallet.mjs
# → { "addresses": { "base": "0x…", "solana": "…", "bitcoin": "bc1…", "tron": "T…" } }

Set BAW_WALLET_FILE to choose where the phrase is stored, or BAW_MNEMONIC to restore an existing one.

View full script source
baw-agent-wallet.mjs
#!/usr/bin/env node
// BuildAWallet agent wallet kit ,  runs locally, never contacts a server.
// Install: npm i @scure/bip39 @scure/bip32 @scure/base @scure/btc-signer @noble/hashes @noble/curves ethers
// Run:     node baw-agent-wallet.mjs            (creates ./baw-wallet.json once)
//          BAW_WALLET_FILE=/secure/path.json node baw-agent-wallet.mjs
import { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english.js";
import { HDKey } from "@scure/bip32";
import { hmac } from "@noble/hashes/hmac.js";
import { sha256, sha512 } from "@noble/hashes/sha2.js";
import { keccak_256 } from "@noble/hashes/sha3.js";
import { secp256k1 } from "@noble/curves/secp256k1.js";
import { ed25519 } from "@noble/curves/ed25519.js";
import { base58 } from "@scure/base";
import * as btc from "@scure/btc-signer";
import { computeAddress } from "ethers";
import { existsSync, readFileSync, writeFileSync, chmodSync } from "node:fs";

const FILE = process.env.BAW_WALLET_FILE || "./baw-wallet.json";
const hex = (b) => "0x" + Buffer.from(b).toString("hex");

function slip10(seed, path) {
  let I = hmac(sha512, new TextEncoder().encode("ed25519 seed"), seed);
  let key = I.slice(0, 32), chain = I.slice(32);
  for (const seg of path.replace(/^m\//, "").split("/")) {
    const data = new Uint8Array(37); data.set(key, 1);
    new DataView(data.buffer).setUint32(33, (parseInt(seg, 10) | 0x80000000) >>> 0, false);
    I = hmac(sha512, chain, data); key = I.slice(0, 32); chain = I.slice(32);
  }
  return key;
}

let mnemonic = process.env.BAW_MNEMONIC;
if (!mnemonic && existsSync(FILE)) mnemonic = JSON.parse(readFileSync(FILE, "utf8")).mnemonic;
if (!mnemonic) {
  mnemonic = generateMnemonic(wordlist, 128);
  writeFileSync(FILE, JSON.stringify({ mnemonic, createdAt: new Date().toISOString() }, null, 2), { mode: 0o600 });
  chmodSync(FILE, 0o600);
}
if (!validateMnemonic(mnemonic.trim(), wordlist)) throw new Error("Invalid recovery phrase");

const seed = mnemonicToSeedSync(mnemonic.trim());
const root = HDKey.fromMasterSeed(seed);
const evm = computeAddress(hex(root.derive("m/44'/60'/0'/0/0").privateKey));
const sol = base58.encode(ed25519.getPublicKey(slip10(seed, "m/44'/501'/0'/0'")));
const bitcoin = btc.p2wpkh(root.derive("m/84'/0'/0'/0/0").publicKey).address;

// Public addresses only. Same EVM address works on every EVM network.
console.log(JSON.stringify({
  walletFile: FILE,
  addresses: {
    ethereum: evm, base: evm, arbitrum: evm, optimism: evm, polygon: evm, bnb: evm, avalanche: evm,
    solana: sol, bitcoin,
  },
  next: "https://buildawallet.xyz/machine/v1/wallets/kit",
}, null, 2));

Option 2

Ask the server to make one

For agents that can only make HTTP calls. Read the warning first.
HTTP
curl -X POST https://buildawallet.xyz/machine/v1/wallets/generate \
  -H 'content-type: application/json' \
  -d '{"acknowledgeCustodyRisk": true, "words": 12}'

The phrase exists briefly on our servers while it's made. We keep no copy, so if it's lost the funds are lost. Anyone who sees it controls the wallet.

Reference

Derivation paths

evm
m/44'/60'/0'/0/0
solana
m/44'/501'/0'/0'
bitcoin
m/84'/0'/0'/0/0

One EVM address covers Ethereum, Base, Arbitrum, Optimism, Polygon, BNB Chain and Avalanche. Bitcoin uses native SegWit (bc1…).