> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anchorage.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Mapping wallets to on-chain addresses

> Map wallet IDs to on-chain addresses across account-based, UTXO, and compatible networks.

export const WalletPlanner = () => {
  const SANS = "Inter, ui-sans-serif, system-ui, sans-serif";
  const MONO = "'Roboto Mono', ui-monospace, SFMono-Regular, monospace";
  const WAM_WIDS = ["8f3a21", "c075d9", "41be8c", "9d2b64", "7c5e19"];
  const WAM_BTC_WID = "2d97bf";
  const wamWid = s => "wallet ID=" + s;
  const WAM_NETS = {
    ethereum: {
      label: "Ethereum",
      family: "EVM",
      model: "account",
      assets: "ETH, ERC-20s",
      chain: ["Ethereum", "Arbitrum", "Base", "Optimism", "Polygon"],
      addr: ["0xA1b2…9F3c", "0x7Dc4…21Ea", "0xF03b…8B7d", "0x5E9a…C412", "0x2b81…7f6D"]
    },
    solana: {
      label: "Solana",
      family: "SVM",
      model: "account",
      assets: "SOL, SPL tokens",
      chain: ["Solana", "Fogo"],
      addr: ["7xKX…gAsU", "9pQm…Lt3V"]
    },
    bitcoin: {
      label: "Bitcoin",
      family: "UTXO",
      model: "utxo",
      assets: "BTC",
      chain: ["Bitcoin"],
      addr: ["bc1q…4k2p", "bc1q…m7ry", "bc1q…s8ez", "bc1q…j0xd"]
    }
  };
  const isDark = () => typeof document !== "undefined" && (document.documentElement.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark");
  const [dark, setDark] = useState(isDark);
  useEffect(() => {
    if (typeof document === "undefined") return;
    const read = () => setDark(isDark());
    read();
    const obs = new MutationObserver(read);
    obs.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class", "data-theme"]
    });
    return () => obs.disconnect();
  }, []);
  const C = dark ? {
    card: "#161718",
    cardBorder: "#222325",
    panel: "#1F1F1F",
    soft: "#1B1C1D",
    strong: "#FFFFFF",
    body: "#CACBCE",
    muted: "#AAACB1",
    line: "#222325",
    edge: "#4E5055",
    anchorage: "#90ACF9",
    anchorageSoft: "#131C34",
    chain: "#5FD6E8",
    chainSoft: "#0B2126",
    auto: "#E4B45C",
    autoSoft: "#271C02",
    termBg: "#0F0F10",
    termInk: "#F4F5F5",
    termMuted: "#8B8F94"
  } : {
    card: "#FFFFFF",
    cardBorder: "#E4E5E7",
    panel: "#FFFFFF",
    soft: "#F4F5F5",
    strong: "#000000",
    body: "#4E5055",
    muted: "#6B6E73",
    line: "#E4E5E7",
    edge: "#AAACB1",
    anchorage: "#2E52C8",
    anchorageSoft: "#F5F8FF",
    chain: "#0E7C8D",
    chainSoft: "#F0FAFB",
    auto: "#886107",
    autoSoft: "#FDF8EC",
    termBg: "#141415",
    termInk: "#F4F5F5",
    termMuted: "#9A9DA2"
  };
  const label = {
    fontFamily: MONO,
    fontSize: "11px",
    letterSpacing: "0.04em",
    color: C.muted,
    fontWeight: 600,
    marginBottom: "10px",
    textTransform: "uppercase"
  };
  const legend = {
    marginTop: "10px",
    fontSize: "11.5px",
    lineHeight: 1.6,
    color: C.muted
  };
  const scroller = {
    overflowX: "auto"
  };
  const svgStyle = {
    width: "100%",
    minWidth: "640px",
    height: "auto",
    display: "block"
  };
  const WamArrow = ({id, color}) => <defs>
      <marker id={id} viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
        <path d="M 0 1 L 9 5 L 0 9 z" fill={color} />
      </marker>
    </defs>;
  const WamSwatch = ({color}) => <span style={{
    display: "inline-block",
    width: "8px",
    height: "8px",
    borderRadius: "2px",
    background: color,
    marginRight: "4px"
  }} />;
  const [network, setNetwork] = useState("ethereum");
  const [reach, setReach] = useState("all");
  const [strategy, setStrategy] = useState("shared");
  const [utxoCount, setUtxoCount] = useState("2");
  const net = WAM_NETS[network];
  const isUtxo = net.model === "utxo";
  const plan = (() => {
    if (isUtxo) {
      const count = parseInt(utxoCount, 10);
      return {
        kind: "utxo",
        wallets: [{
          net: "Bitcoin",
          wid: WAM_BTC_WID,
          assets: net.assets
        }],
        addresses: net.addr.slice(0, count).map((v, i) => ({
          v,
          auto: i > 0
        })),
        map: () => true
      };
    }
    const k = reach === "only" ? 1 : net.chain.length;
    const nets = net.chain.slice(0, k);
    const shared = strategy === "shared" || k === 1;
    return {
      kind: shared ? "shared" : "unique",
      wallets: nets.map((n, i) => ({
        net: n,
        wid: WAM_WIDS[i % WAM_WIDS.length],
        assets: n === "Polygon" ? "POL, ERC-20s" : net.assets
      })),
      addresses: shared ? [{
        v: net.addr[0],
        auto: false
      }] : nets.map((_, i) => ({
        v: net.addr[i % net.addr.length],
        auto: false
      })),
      map: (wi, ai) => shared ? ai === 0 : wi === ai
    };
  })();
  const caseName = plan.kind === "utxo" ? "UTXO" : plan.wallets.length === 1 ? "one network" : plan.kind === "shared" ? "compatible networks, shared address" : "compatible networks, address per network";
  const lane = (count, y, h, maxW) => {
    const span = 880, x0 = 60, gap = 14;
    const w = Math.min(maxW, (span - (count - 1) * gap) / count);
    const total = count * w + (count - 1) * gap;
    const start = x0 + (span - total) / 2;
    const out = [];
    for (let i = 0; i < count; i++) {
      const x = start + i * (w + gap);
      out.push({
        x,
        y,
        w,
        h,
        cx: x + w / 2
      });
    }
    return out;
  };
  const W = lane(plan.wallets.length, 58, 66, 200);
  const A = lane(plan.addresses.length, 262, 62, 200);
  const edges = [];
  W.forEach((w, wi) => {
    A.forEach((a, ai) => {
      if (!plan.map(wi, ai)) return;
      const y1 = w.y + w.h, y2 = a.y - 6, mid = 200;
      edges.push(Math.abs(w.cx - a.cx) < 0.5 ? "M " + w.cx + " " + y1 + " L " + w.cx + " " + y2 : "M " + w.cx + " " + y1 + " L " + w.cx + " " + mid + " L " + a.cx + " " + mid + " L " + a.cx + " " + y2);
    });
  });
  const cardinality = plan.wallets.length + (plan.wallets.length === 1 ? " wallet ID : " : " wallet IDs : ") + plan.addresses.length + (plan.addresses.length === 1 ? " address" : " addresses");
  const planFoot = plan.kind === "utxo" ? "Every address receives, and all of them pool into one balance under one wallet ID." : plan.kind === "shared" ? plan.wallets.length > 1 ? "Edges converge: several wallet IDs behind one on-chain address." : "One wallet, one address." : "Parallel edges: each network has its own on-chain address.";
  const segBtn = (on, off) => ({
    flex: "1 1 0",
    minWidth: 0,
    border: "none",
    borderRadius: "8px",
    padding: "7px 6px",
    fontFamily: SANS,
    fontSize: "12.5px",
    fontWeight: 600,
    cursor: off ? "not-allowed" : "pointer",
    opacity: off ? 0.4 : 1,
    background: on ? C.panel : "transparent",
    color: on ? C.strong : C.body,
    boxShadow: on ? "0 1px 2px rgba(0,0,0,0.08)" : "none"
  });
  const Seg = ({title, note, options, value, onPick, disabled}) => <div style={{
    minWidth: "200px",
    flex: "1 1 200px"
  }}>
      <div style={{
    fontSize: "11px",
    letterSpacing: "0.06em",
    color: C.muted,
    marginBottom: "6px",
    fontWeight: 600,
    textTransform: "uppercase"
  }}>{title}</div>
      <div style={{
    display: "flex",
    background: C.soft,
    border: "1px solid " + C.line,
    borderRadius: "10px",
    padding: "3px",
    gap: "3px"
  }}>
        {options.map(o => <button key={o.v} type="button" style={segBtn(value === o.v, disabled)} aria-pressed={value === o.v} disabled={disabled} onClick={() => {
    if (!disabled) onPick(o.v);
  }}>{o.t}</button>)}
      </div>
      <div style={{
    fontSize: "11px",
    color: C.muted,
    marginTop: "5px",
    lineHeight: 1.45
  }}>{note}</div>
    </div>;
  const summaryLines = (() => {
    const out = [["Wallets to create", plan.wallets.map(w => w.net).join(", ")]];
    if (plan.kind === "utxo") {
      out.push(["Addresses", "one to start, then as many as you generate, all pooled"]);
      out.push(["Assets", "BTC only, because a UTXO network has no token layer to share the address with"]);
    } else if (plan.wallets.length === 1) {
      out.push(["Addresses", "exactly one, so a second address means a second wallet"]);
      out.push(["Assets", net.assets + ", sharing this wallet ID"]);
    } else {
      out.push(["Addresses", plan.kind === "shared" ? "one, shared by every wallet above" : "one per network, none shared"]);
      out.push(["Balances", "tracked per wallet ID, and a withdrawal names a wallet ID"]);
    }
    return out;
  })();
  const holdRows = (() => {
    const out = [["Withdrawing", "A withdrawal names a wallet ID. The first wallet created for a network in a vault is that vault's default wallet, and the source of funds for external withdrawals."]];
    if (plan.kind === "utxo") {
      out.push(["Choosing a source", "You never designate an address. Funds are pulled from multiple addresses automatically."]);
      out.push(["Change addresses", "A transfer returns its unspent remainder to a new address inside this wallet, managed for you and counted in the balance."]);
      out.push(["Allowlisting", "Trusted destinations are per network, so one Bitcoin entry covers withdrawals from this wallet."]);
    } else if (plan.wallets.length === 1) {
      out.push(["Another address", "On an account-based network, a second deposit address means a second wallet with its own wallet ID."]);
      out.push(["Token deposits", "Every token on this network uses this same deposit address, while balances stay separate per asset."]);
      out.push(["Allowlisting", "Trusted destinations are per network, so add this network's entry before withdrawing."]);
    } else {
      out.push(["Moving between networks", "Balances never cross networks on their own. Getting funds from " + plan.wallets[0].net + " to " + plan.wallets[1].net + " means bridging."]);
      out.push(["Allowlisting", plan.kind === "shared" ? "Per network, always: the same address on " + plan.wallets[0].net + " and " + plan.wallets[1].net + " are two separate trusted destinations." : "Per network, always, and here each network has its own address to allowlist."]);
      out.push([plan.kind === "shared" ? "On-chain visibility" : "Privacy", plan.kind === "shared" ? "One address carries activity for all " + plan.wallets.length + " networks, so anyone watching it sees the whole set." : "Separate addresses keep these networks unlinked on chain. To get a fresh address in a family, create more wallets than you already hold in it."]);
      out.push(["Unexpected deposits", "A deposit on a compatible network where you have no wallet is still detected on the shared address. We run spam attribution and create the wallet if it clears."]);
    }
    return out;
  })();
  const card = {
    background: C.panel,
    border: "1px solid " + C.line,
    borderRadius: "14px",
    padding: "16px"
  };
  return <div style={{
    background: dark ? C.soft : "#F4F5F5",
    border: "1px solid " + C.cardBorder,
    borderRadius: "14px",
    padding: "16px",
    margin: "1.5rem 0",
    fontFamily: SANS
  }}>
      <div style={{
    ...card,
    display: "flex",
    gap: "18px",
    flexWrap: "wrap",
    marginBottom: "14px"
  }}>
        <Seg title="1 · Network" note={isUtxo ? "UTXO. One asset, many addresses." : "Account-based. " + net.family + " family, " + net.chain.length + " compatible networks."} options={[{
    v: "ethereum",
    t: "Ethereum"
  }, {
    v: "solana",
    t: "Solana"
  }, {
    v: "bitcoin",
    t: "Bitcoin"
  }]} value={network} onPick={v => {
    setNetwork(v);
    if (WAM_NETS[v].model === "utxo") setReach("only");
  }} />

        <Seg title="2 · Networks to cover" note={isUtxo ? "UTXO networks share no addresses across networks." : reach === "only" ? "One network, one wallet ID." : "Covers " + net.chain.join(", ") + "."} options={[{
    v: "only",
    t: "This one"
  }, {
    v: "all",
    t: "All"
  }]} value={reach} onPick={setReach} disabled={isUtxo} />

        <Seg title="3 · Address strategy" note={isUtxo ? "Not applicable." : reach === "only" ? "Applies once more than one network is covered." : strategy === "shared" ? "Option B above." : "Option A above."} options={[{
    v: "shared",
    t: "Shared"
  }, {
    v: "unique",
    t: "Unique"
  }]} value={strategy} onPick={setStrategy} disabled={isUtxo || reach === "only"} />

        <Seg title="4 · Addresses generated" note={isUtxo ? "Generate more at any time, all pooled to this wallet." : "Applies to UTXO networks only."} options={[{
    v: "1",
    t: "1"
  }, {
    v: "2",
    t: "2"
  }, {
    v: "4",
    t: "4"
  }]} value={utxoCount} onPick={setUtxoCount} disabled={!isUtxo} />
      </div>

      <div style={card}>
        <div style={label}>Resulting structure: {caseName}</div>
        <div style={scroller}>
          <svg viewBox="0 0 1000 380" style={svgStyle} fontFamily={SANS} role="img" aria-label={"Generated diagram. " + cardinality + ". " + planFoot}>
            <WamArrow id="wam-plan" color={C.edge} />
            <text x="0" y="14" fontFamily={MONO} fontSize="9.5" letterSpacing="0.9" fill={C.muted}>ANCHORAGE DIGITAL · wallet ID</text>
            <text x="0" y="248" fontFamily={MONO} fontSize="9.5" letterSpacing="0.9" fill={C.muted}>ON CHAIN · address</text>
            <text x="1000" y="14" textAnchor="end" fontFamily={MONO} fontSize="11.5" fontWeight="700" fill={C.anchorage}>{cardinality}</text>

            {edges.map((d, i) => <path key={i} d={d} stroke={C.edge} strokeWidth="1.4" fill="none" markerEnd="url(#wam-plan)" />)}

            {W.map((w, i) => <g key={"w" + i}>
                <rect x={w.x} y={w.y} width={w.w} height={w.h} rx="9" fill={C.anchorageSoft} stroke={C.anchorage} strokeWidth="1.5" />
                <text x={w.cx} y={w.y + 22} textAnchor="middle" fontSize="11" fontWeight="600" fill={C.strong}>{plan.wallets[i].net}</text>
                <text x={w.cx} y={w.y + 40} textAnchor="middle" fontFamily={MONO} fontSize="9.5" fill={C.anchorage}>{wamWid(plan.wallets[i].wid)}</text>
                <text x={w.cx} y={w.y + 56} textAnchor="middle" fontSize="9.5" fill={C.muted}>{plan.wallets[i].assets}</text>
              </g>)}

            {A.map((a, i) => <g key={"a" + i}>
                <rect x={a.x} y={a.y} width={a.w} height={a.h} rx="9" fill={plan.addresses[i].auto ? C.autoSoft : C.chainSoft} stroke={plan.addresses[i].auto ? C.auto : C.chain} strokeWidth="1.2" strokeDasharray="5 4" />
                <text x={a.cx} y={a.y + 26} textAnchor="middle" fontFamily={MONO} fontSize="10.5" fill={plan.addresses[i].auto ? C.auto : C.chain}>{plan.addresses[i].v}</text>
                <text x={a.cx} y={a.y + 44} textAnchor="middle" fontSize="9.5" fill={plan.addresses[i].auto ? C.auto : C.muted}>
                  {plan.addresses[i].auto ? "generated, pooled" : plan.kind === "utxo" ? "deposit" : "deposit address"}
                </text>
              </g>)}

            <text x="500" y="358" textAnchor="middle" fontSize="10.5" fill={C.muted}>{planFoot}</text>
          </svg>
        </div>
        <div style={legend}>
          <WamSwatch color={C.anchorage} />Wallets on top  
          <WamSwatch color={C.chain} />addresses below  
          <WamSwatch color={C.auto} />generated for you.   Edges that converge on one address are the n : 1 case.
        </div>
      </div>

      <div style={{
    display: "flex",
    gap: "14px",
    marginTop: "14px",
    flexWrap: "wrap"
  }}>
        <div style={{
    ...card,
    flex: "1 1 340px",
    borderLeft: "4px solid " + C.chain,
    padding: "14px 16px"
  }}>
          <div style={label}>What you end up with</div>
          <div style={{
    display: "flex",
    gap: "10px",
    flexWrap: "wrap",
    marginBottom: "10px"
  }}>
            {[[plan.wallets.length, "Wallets", C.anchorage], [plan.addresses.length, "On-chain addresses", C.chain], [new Set(plan.wallets.map(w => w.net)).size, "Networks", C.anchorage]].map(k => <div key={k[1]} style={{
    flex: "1 1 90px"
  }}>
                <div style={{
    fontFamily: MONO,
    fontSize: "20px",
    color: k[2],
    fontVariantNumeric: "tabular-nums"
  }}>{k[0]}</div>
                <div style={{
    fontSize: "10.5px",
    color: C.muted,
    textTransform: "uppercase",
    letterSpacing: "0.04em"
  }}>{k[1]}</div>
              </div>)}
          </div>
          {summaryLines.map(l => <div key={l[0]} style={{
    fontSize: "12.5px",
    lineHeight: 1.55,
    color: C.body,
    marginBottom: "6px"
  }}>
              <strong style={{
    color: C.strong
  }}>{l[0]}:</strong> {l[1]}.
            </div>)}
        </div>

        <div style={{
    ...card,
    flex: "1 1 340px",
    padding: "14px 16px"
  }}>
          <div style={label}>As the API would list it</div>
          <div style={{
    fontFamily: MONO,
    fontSize: "12px",
    background: C.termBg,
    color: C.termInk,
    borderRadius: "12px",
    padding: "12px 14px",
    maxHeight: "240px",
    overflow: "auto",
    lineHeight: 1.6
  }}>
            <div style={{
    color: C.termMuted
  }}>GET /v2/wallets</div>
            {plan.kind === "utxo" ? <div style={{
    display: "flex",
    gap: "12px",
    whiteSpace: "nowrap"
  }}>
                <span style={{
    width: "152px",
    flexShrink: 0
  }}>{wamWid(plan.wallets[0].wid)}</span>
                <span style={{
    width: "92px",
    flexShrink: 0,
    color: C.termMuted
  }}>BITCOIN</span>
                <span style={{
    flex: 1
  }}>{plan.addresses.map(a => a.v).join(", ")}</span>
              </div> : plan.wallets.map((w, i) => <div key={w.wid} style={{
    display: "flex",
    gap: "12px",
    whiteSpace: "nowrap"
  }}>
                <span style={{
    width: "152px",
    flexShrink: 0
  }}>{wamWid(w.wid)}</span>
                <span style={{
    width: "92px",
    flexShrink: 0,
    color: C.termMuted
  }}>{w.net.toUpperCase()}</span>
                <span style={{
    flex: 1
  }}>{plan.addresses[plan.kind === "shared" ? 0 : i].v}</span>
              </div>)}
            <div style={{
    color: C.termMuted,
    marginTop: "8px",
    whiteSpace: "normal"
  }}>
              {plan.kind === "utxo" ? "One wallet, " + plan.addresses.length + " address" + (plan.addresses.length === 1 ? "" : "es") + ". Deposit-address listings return every one of them." : plan.wallets.length === 1 ? "One wallet, one address." : plan.kind === "shared" ? "Separate wallet IDs, identical address. Filtering by address returns all " + plan.wallets.length + " wallets." : "Separate wallet IDs, separate addresses. Nothing correlates these on chain."}
            </div>
          </div>
        </div>
      </div>

      <div style={{
    ...card,
    marginTop: "14px"
  }}>
        <div style={label}>What this means for this configuration</div>
        <div style={{
    display: "grid",
    gridTemplateColumns: "repeat(auto-fit, minmax(230px, 1fr))",
    gap: "0 20px"
  }}>
          {holdRows.map(r => <div key={r[0]} style={{
    padding: "8px 0",
    borderTop: "1px solid " + C.line
  }}>
              <div style={{
    fontSize: "11.5px",
    fontWeight: 700,
    color: C.anchorage,
    marginBottom: "2px"
  }}>{r[0]}</div>
              <div style={{
    fontSize: "12.5px",
    lineHeight: 1.5,
    color: C.body
  }}>{r[1]}</div>
            </div>)}
        </div>
      </div>
    </div>;
};

export const CompatibleNetworkOptions = () => {
  const SANS = "Inter, ui-sans-serif, system-ui, sans-serif";
  const MONO = "'Roboto Mono', ui-monospace, SFMono-Regular, monospace";
  const wamWid = s => "wallet ID=" + s;
  const isDark = () => typeof document !== "undefined" && (document.documentElement.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark");
  const [dark, setDark] = useState(isDark);
  useEffect(() => {
    if (typeof document === "undefined") return;
    const read = () => setDark(isDark());
    read();
    const obs = new MutationObserver(read);
    obs.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class", "data-theme"]
    });
    return () => obs.disconnect();
  }, []);
  const C = dark ? {
    card: "#161718",
    cardBorder: "#222325",
    panel: "#1F1F1F",
    soft: "#1B1C1D",
    strong: "#FFFFFF",
    body: "#CACBCE",
    muted: "#AAACB1",
    line: "#222325",
    edge: "#4E5055",
    anchorage: "#90ACF9",
    anchorageSoft: "#131C34",
    chain: "#5FD6E8",
    chainSoft: "#0B2126",
    auto: "#E4B45C",
    autoSoft: "#271C02",
    termBg: "#0F0F10",
    termInk: "#F4F5F5",
    termMuted: "#8B8F94"
  } : {
    card: "#FFFFFF",
    cardBorder: "#E4E5E7",
    panel: "#FFFFFF",
    soft: "#F4F5F5",
    strong: "#000000",
    body: "#4E5055",
    muted: "#6B6E73",
    line: "#E4E5E7",
    edge: "#AAACB1",
    anchorage: "#2E52C8",
    anchorageSoft: "#F5F8FF",
    chain: "#0E7C8D",
    chainSoft: "#F0FAFB",
    auto: "#886107",
    autoSoft: "#FDF8EC",
    termBg: "#141415",
    termInk: "#F4F5F5",
    termMuted: "#9A9DA2"
  };
  const panel = {
    background: C.panel,
    border: "1px solid " + C.cardBorder,
    borderRadius: "14px",
    padding: "16px",
    margin: "1.5rem 0",
    fontFamily: SANS
  };
  const label = {
    fontFamily: MONO,
    fontSize: "11px",
    letterSpacing: "0.04em",
    color: C.muted,
    fontWeight: 600,
    marginBottom: "10px",
    textTransform: "uppercase"
  };
  const legend = {
    marginTop: "10px",
    fontSize: "11.5px",
    lineHeight: 1.6,
    color: C.muted
  };
  const scroller = {
    overflowX: "auto"
  };
  const svgStyle = {
    width: "100%",
    minWidth: "640px",
    height: "auto",
    display: "block"
  };
  const WamArrow = ({id, color}) => <defs>
      <marker id={id} viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
        <path d="M 0 1 L 9 5 L 0 9 z" fill={color} />
      </marker>
    </defs>;
  const rows = [{
    y: 40,
    name: "Ethereum",
    w: "8f3a21",
    a: "0xA1b2…9F3c"
  }, {
    y: 92,
    name: "Arbitrum",
    w: "c075d9",
    a: "0x7Dc4…21Ea"
  }, {
    y: 144,
    name: "Base",
    w: "41be8c",
    a: "0xF03b…8B7d"
  }];
  return <div style={panel}>
      <div style={label}>Separate addresses vs one shared address</div>
      <div style={scroller}>
        <svg viewBox="0 0 1000 300" style={svgStyle} fontFamily={SANS} role="img" aria-label="Option A: three wallets on Ethereum, Arbitrum, and Base, each with its own wallet ID and its own separate on-chain address. Option B: the same three wallets with their own wallet IDs all sharing a single on-chain address.">
          <WamArrow id="wam-a3" color={C.edge} />

          <text x="0" y="14" fontFamily={MONO} fontSize="9.5" letterSpacing="0.9" fill={C.muted}>OPTION A · AN ADDRESS PER NETWORK</text>
          {rows.map(r => <g key={r.name}>
              <rect x="0" y={r.y} width="226" height="40" rx="8" fill={C.anchorageSoft} stroke={C.anchorage} strokeWidth="1.5" />
              <text x="14" y={r.y + 25} fontSize="10.5" fontWeight="600" fill={C.strong}>{r.name}</text>
              <text x="212" y={r.y + 25} textAnchor="end" fontFamily={MONO} fontSize="9.5" fill={C.anchorage}>{wamWid(r.w)}</text>
              <line x1="226" y1={r.y + 20} x2="252" y2={r.y + 20} stroke={C.edge} strokeWidth="1.3" markerEnd="url(#wam-a3)" />
              <rect x="258" y={r.y} width="212" height="40" rx="8" fill={C.chainSoft} stroke={C.chain} strokeWidth="1.2" strokeDasharray="5 4" />
              <text x="364" y={r.y + 25} textAnchor="middle" fontFamily={MONO} fontSize="10" fill={C.chain}>{r.a}</text>
            </g>)}
          <text x="235" y="230" textAnchor="middle" fontFamily={MONO} fontSize="12" fontWeight="700" fill={C.anchorage}>3 wallet IDs : 3 addresses</text>
          <text x="235" y="256" textAnchor="middle" fontSize="10.5" fill={C.muted}>Nothing links these networks on chain.</text>
          <text x="235" y="272" textAnchor="middle" fontSize="10.5" fill={C.muted}>Three addresses to distribute and allowlist.</text>

          <line x1="500" y1="30" x2="500" y2="284" stroke={C.line} strokeWidth="1" />

          <text x="530" y="14" fontFamily={MONO} fontSize="9.5" letterSpacing="0.9" fill={C.muted}>OPTION B · ONE ADDRESS FOR THE FAMILY</text>
          {rows.map(r => <g key={"b" + r.name}>
              <rect x="530" y={r.y} width="226" height="40" rx="8" fill={C.anchorageSoft} stroke={C.anchorage} strokeWidth="1.5" />
              <text x="544" y={r.y + 25} fontSize="10.5" fontWeight="600" fill={C.strong}>{r.name}</text>
              <text x="742" y={r.y + 25} textAnchor="end" fontFamily={MONO} fontSize="9.5" fill={C.anchorage}>{wamWid(r.w)}</text>
            </g>)}
          <path d="M 756 60 L 772 60 L 772 164 L 756 164" stroke={C.edge} strokeWidth="1.3" fill="none" />
          <line x1="756" y1="112" x2="772" y2="112" stroke={C.edge} strokeWidth="1.3" />
          <line x1="772" y1="112" x2="800" y2="112" stroke={C.edge} strokeWidth="1.3" markerEnd="url(#wam-a3)" />

          <rect x="806" y="86" width="194" height="52" rx="9" fill={C.chainSoft} stroke={C.chain} strokeWidth="1.2" strokeDasharray="5 4" />
          <text x="903" y="108" textAnchor="middle" fontFamily={MONO} fontSize="10.5" fill={C.chain}>0xA1b2…9F3c</text>
          <text x="903" y="125" textAnchor="middle" fontSize="9.5" fill={C.muted}>one address, shared</text>

          <text x="765" y="230" textAnchor="middle" fontFamily={MONO} fontSize="12" fontWeight="700" fill={C.anchorage}>3 wallet IDs : 1 address</text>
          <text x="765" y="256" textAnchor="middle" fontSize="10.5" fill={C.muted}>One address for counterparties to use.</text>
          <text x="765" y="272" textAnchor="middle" fontSize="10.5" fill={C.muted}>Anyone watching it sees all three networks.</text>
        </svg>
      </div>
      <div style={legend}>
        You don’t have to create the wallet first. If you deposit a token on a compatible network where you have no wallet for it yet, we generate one: we detect the balance on the shared address, run spam attribution, and create the wallet on that network if the deposit clears. Spam deposits never generate wallets.
      </div>
    </div>;
};

export const AddressAssetTypes = () => {
  const SANS = "Inter, ui-sans-serif, system-ui, sans-serif";
  const MONO = "'Roboto Mono', ui-monospace, SFMono-Regular, monospace";
  const wamWid = s => "wallet ID=" + s;
  const isDark = () => typeof document !== "undefined" && (document.documentElement.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark");
  const [dark, setDark] = useState(isDark);
  useEffect(() => {
    if (typeof document === "undefined") return;
    const read = () => setDark(isDark());
    read();
    const obs = new MutationObserver(read);
    obs.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class", "data-theme"]
    });
    return () => obs.disconnect();
  }, []);
  const C = dark ? {
    card: "#161718",
    cardBorder: "#222325",
    panel: "#1F1F1F",
    soft: "#1B1C1D",
    strong: "#FFFFFF",
    body: "#CACBCE",
    muted: "#AAACB1",
    line: "#222325",
    edge: "#4E5055",
    anchorage: "#90ACF9",
    anchorageSoft: "#131C34",
    chain: "#5FD6E8",
    chainSoft: "#0B2126",
    auto: "#E4B45C",
    autoSoft: "#271C02",
    termBg: "#0F0F10",
    termInk: "#F4F5F5",
    termMuted: "#8B8F94"
  } : {
    card: "#FFFFFF",
    cardBorder: "#E4E5E7",
    panel: "#FFFFFF",
    soft: "#F4F5F5",
    strong: "#000000",
    body: "#4E5055",
    muted: "#6B6E73",
    line: "#E4E5E7",
    edge: "#AAACB1",
    anchorage: "#2E52C8",
    anchorageSoft: "#F5F8FF",
    chain: "#0E7C8D",
    chainSoft: "#F0FAFB",
    auto: "#886107",
    autoSoft: "#FDF8EC",
    termBg: "#141415",
    termInk: "#F4F5F5",
    termMuted: "#9A9DA2"
  };
  const panel = {
    background: C.panel,
    border: "1px solid " + C.cardBorder,
    borderRadius: "14px",
    padding: "16px",
    margin: "1.5rem 0",
    fontFamily: SANS
  };
  const label = {
    fontFamily: MONO,
    fontSize: "11px",
    letterSpacing: "0.04em",
    color: C.muted,
    fontWeight: 600,
    marginBottom: "10px",
    textTransform: "uppercase"
  };
  const legend = {
    marginTop: "10px",
    fontSize: "11.5px",
    lineHeight: 1.6,
    color: C.muted
  };
  const scroller = {
    overflowX: "auto"
  };
  const svgStyle = {
    width: "100%",
    minWidth: "640px",
    height: "auto",
    display: "block"
  };
  const WamArrow = ({id, color}) => <defs>
      <marker id={id} viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
        <path d="M 0 1 L 9 5 L 0 9 z" fill={color} />
      </marker>
    </defs>;
  const chips = [{
    x: 314,
    w: 78,
    t: "ETH",
    dash: false
  }, {
    x: 400,
    w: 84,
    t: "USDC",
    dash: false
  }, {
    x: 492,
    w: 84,
    t: "USDT",
    dash: false
  }, {
    x: 584,
    w: 84,
    t: "WBTC",
    dash: false
  }, {
    x: 676,
    w: 118,
    t: "any ERC-20",
    dash: true
  }];
  return <div style={panel}>
      <div style={label}>One address, many asset types</div>
      <div style={scroller}>
        <svg viewBox="0 0 1000 232" style={svgStyle} fontFamily={SANS} role="img" aria-label="One Ethereum on-chain address feeds a single wallet under one wallet ID, holding ETH, USDC, USDT, WBTC, and any other ERC-20 token, each with its own balance.">
          <WamArrow id="wam-a2" color={C.edge} />

          <text x="0" y="14" fontFamily={MONO} fontSize="9.5" letterSpacing="0.9" fill={C.muted}>ACCOUNT-BASED · ETHEREUM</text>

          <rect x="0" y="76" width="236" height="72" rx="9" fill={C.chainSoft} stroke={C.chain} strokeWidth="1.2" strokeDasharray="5 4" />
          <text x="118" y="106" textAnchor="middle" fontFamily={MONO} fontSize="11.5" fill={C.chain}>0xA1b2…9F3c</text>
          <text x="118" y="124" textAnchor="middle" fontSize="10" fill={C.muted}>one on-chain address</text>

          <line x1="236" y1="112" x2="286" y2="112" stroke={C.edge} strokeWidth="1.4" markerEnd="url(#wam-a2)" />

          <rect x="292" y="44" width="708" height="136" rx="9" fill={C.anchorageSoft} stroke={C.anchorage} strokeWidth="1.5" />
          <text x="314" y="70" fontSize="11.5" fontWeight="600" fill={C.strong}>Anchorage Digital wallet, Ethereum</text>
          <text x="978" y="70" textAnchor="end" fontFamily={MONO} fontSize="10.5" fill={C.anchorage}>{wamWid("8f3a21")}</text>

          {chips.map(c => <g key={c.t}>
              <rect x={c.x} y="86" width={c.w} height="28" rx="6" fill={C.card} stroke={C.edge} strokeDasharray={c.dash ? "4 3" : null} />
              <text x={c.x + c.w / 2} y="105" textAnchor="middle" fontFamily={MONO} fontSize="10.5" fill={c.dash ? C.muted : C.strong}>{c.t}</text>
            </g>)}

          <text x="314" y="140" fontSize="10.5" fill={C.body}>ETH is the network’s native asset. The rest are tokens issued on Ethereum.</text>
          <text x="314" y="158" fontSize="10.5" fill={C.body}>They share this address and this wallet ID, and each keeps its own balance.</text>

          <text x="500" y="214" textAnchor="middle" fontFamily={MONO} fontSize="12" fontWeight="700" fill={C.anchorage}>1 address · 1 wallet ID · many asset types</text>
        </svg>
      </div>
      <div style={legend}>
        Ethereum here, but this holds on any account-based network, such as Solana with its SPL tokens. To get a second deposit address you create a second wallet, which comes with its own wallet ID.
      </div>
    </div>;
};

export const WalletAddressMap = () => {
  const SANS = "Inter, ui-sans-serif, system-ui, sans-serif";
  const MONO = "'Roboto Mono', ui-monospace, SFMono-Regular, monospace";
  const WAM_BTC_WID = "2d97bf";
  const wamWid = s => "wallet ID=" + s;
  const isDark = () => typeof document !== "undefined" && (document.documentElement.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark");
  const [dark, setDark] = useState(isDark);
  useEffect(() => {
    if (typeof document === "undefined") return;
    const read = () => setDark(isDark());
    read();
    const obs = new MutationObserver(read);
    obs.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class", "data-theme"]
    });
    return () => obs.disconnect();
  }, []);
  const C = dark ? {
    card: "#161718",
    cardBorder: "#222325",
    panel: "#1F1F1F",
    soft: "#1B1C1D",
    strong: "#FFFFFF",
    body: "#CACBCE",
    muted: "#AAACB1",
    line: "#222325",
    edge: "#4E5055",
    anchorage: "#90ACF9",
    anchorageSoft: "#131C34",
    chain: "#5FD6E8",
    chainSoft: "#0B2126",
    auto: "#E4B45C",
    autoSoft: "#271C02",
    termBg: "#0F0F10",
    termInk: "#F4F5F5",
    termMuted: "#8B8F94"
  } : {
    card: "#FFFFFF",
    cardBorder: "#E4E5E7",
    panel: "#FFFFFF",
    soft: "#F4F5F5",
    strong: "#000000",
    body: "#4E5055",
    muted: "#6B6E73",
    line: "#E4E5E7",
    edge: "#AAACB1",
    anchorage: "#2E52C8",
    anchorageSoft: "#F5F8FF",
    chain: "#0E7C8D",
    chainSoft: "#F0FAFB",
    auto: "#886107",
    autoSoft: "#FDF8EC",
    termBg: "#141415",
    termInk: "#F4F5F5",
    termMuted: "#9A9DA2"
  };
  const panel = {
    background: C.panel,
    border: "1px solid " + C.cardBorder,
    borderRadius: "14px",
    padding: "16px",
    margin: "1.5rem 0",
    fontFamily: SANS
  };
  const label = {
    fontFamily: MONO,
    fontSize: "11px",
    letterSpacing: "0.04em",
    color: C.muted,
    fontWeight: 600,
    marginBottom: "10px",
    textTransform: "uppercase"
  };
  const legend = {
    marginTop: "10px",
    fontSize: "11.5px",
    lineHeight: 1.6,
    color: C.muted
  };
  const scroller = {
    overflowX: "auto"
  };
  const svgStyle = {
    width: "100%",
    minWidth: "640px",
    height: "auto",
    display: "block"
  };
  const WamArrow = ({id, color}) => <defs>
      <marker id={id} viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
        <path d="M 0 1 L 9 5 L 0 9 z" fill={color} />
      </marker>
    </defs>;
  const WamSwatch = ({color}) => <span style={{
    display: "inline-block",
    width: "8px",
    height: "8px",
    borderRadius: "2px",
    background: color,
    marginRight: "4px"
  }} />;
  const wallet = (x, y, w, h) => <rect x={x} y={y} width={w} height={h} rx="9" fill={C.anchorageSoft} stroke={C.anchorage} strokeWidth="1.5" />;
  const addr = (x, y, w, h, auto) => <rect x={x} y={y} width={w} height={h} rx="9" fill={auto ? C.autoSoft : C.chainSoft} stroke={auto ? C.auto : C.chain} strokeWidth="1.2" strokeDasharray="5 4" />;
  return <div style={panel}>
      <div style={label}>Account-based vs UTXO</div>
      <div style={scroller}>
        <svg viewBox="0 0 1000 300" style={svgStyle} fontFamily={SANS} role="img" aria-label="Left: one Ethereum wallet with one wallet ID maps to exactly one on-chain address. Right: one Bitcoin wallet with one wallet ID maps to three on-chain addresses, one of them generated automatically as change.">
          <WamArrow id="wam-a1" color={C.edge} />

          <text x="0" y="14" fontFamily={MONO} fontSize="9.5" letterSpacing="0.9" fill={C.muted}>ACCOUNT-BASED · ETHEREUM</text>
          {wallet(95, 40, 280, 58)}
          <text x="235" y="65" textAnchor="middle" fontSize="11.5" fontWeight="600" fill={C.strong}>Anchorage Digital wallet</text>
          <text x="235" y="85" textAnchor="middle" fontFamily={MONO} fontSize="11" fill={C.anchorage}>{wamWid("8f3a21")}</text>

          <line x1="235" y1="98" x2="235" y2="150" stroke={C.edge} strokeWidth="1.4" markerEnd="url(#wam-a1)" />
          <text x="245" y="128" fontFamily={MONO} fontSize="9.5" fill={C.muted}>maps to</text>

          {addr(95, 156, 280, 58)}
          <text x="235" y="181" textAnchor="middle" fontFamily={MONO} fontSize="11.5" fill={C.chain}>0xA1b2…9F3c</text>
          <text x="235" y="199" textAnchor="middle" fontSize="10" fill={C.muted}>the only on-chain address</text>

          <text x="235" y="250" textAnchor="middle" fontFamily={MONO} fontSize="12" fontWeight="700" fill={C.anchorage}>1 wallet ID : 1 address</text>
          <text x="235" y="274" textAnchor="middle" fontSize="10.5" fill={C.muted}>A second address means a second wallet, with a second wallet ID.</text>

          <line x1="500" y1="34" x2="500" y2="282" stroke={C.line} strokeWidth="1" />

          <text x="560" y="14" fontFamily={MONO} fontSize="9.5" letterSpacing="0.9" fill={C.muted}>UTXO · BITCOIN</text>
          {wallet(630, 40, 280, 58)}
          <text x="770" y="65" textAnchor="middle" fontSize="11.5" fontWeight="600" fill={C.strong}>Anchorage Digital wallet</text>
          <text x="770" y="85" textAnchor="middle" fontFamily={MONO} fontSize="11" fill={C.anchorage}>{wamWid(WAM_BTC_WID)}</text>

          <path d="M 770 98 L 770 126" stroke={C.edge} strokeWidth="1.4" fill="none" />
          <line x1="640" y1="126" x2="900" y2="126" stroke={C.edge} strokeWidth="1.4" />
          <g stroke={C.edge} strokeWidth="1.4" markerEnd="url(#wam-a1)">
            <line x1="640" y1="126" x2="640" y2="150" />
            <line x1="770" y1="126" x2="770" y2="150" />
            <line x1="900" y1="126" x2="900" y2="150" />
          </g>
          <text x="782" y="118" fontFamily={MONO} fontSize="9.5" fill={C.muted}>maps to</text>

          {addr(578, 156, 124, 58)}
          <text x="640" y="181" textAnchor="middle" fontFamily={MONO} fontSize="10.5" fill={C.chain}>bc1q…4k2p</text>
          <text x="640" y="199" textAnchor="middle" fontSize="10" fill={C.muted}>deposit</text>

          {addr(708, 156, 124, 58)}
          <text x="770" y="181" textAnchor="middle" fontFamily={MONO} fontSize="10.5" fill={C.chain}>bc1q…m7ry</text>
          <text x="770" y="199" textAnchor="middle" fontSize="10" fill={C.muted}>deposit</text>

          {addr(838, 156, 124, 58, true)}
          <text x="900" y="181" textAnchor="middle" fontFamily={MONO} fontSize="10.5" fill={C.auto}>bc1q…s8ez</text>
          <text x="900" y="199" textAnchor="middle" fontSize="10" fill={C.auto}>change, automatic</text>

          <text x="770" y="250" textAnchor="middle" fontFamily={MONO} fontSize="12" fontWeight="700" fill={C.anchorage}>1 wallet ID : n addresses</text>
          <text x="770" y="274" textAnchor="middle" fontSize="10.5" fill={C.muted}>All of them receive, and all of them pool into one balance.</text>
        </svg>
      </div>
      <div style={legend}>
        <WamSwatch color={C.anchorage} />Wallets and wallet IDs.  
        <WamSwatch color={C.chain} />On-chain addresses.  
        <WamSwatch color={C.auto} />Generated for you: a UTXO transfer returns its unspent remainder to a new change address inside the same wallet.
      </div>
    </div>;
};

An Anchorage Digital wallet isn't necessarily an on-chain address. Sometimes the two line up one to one, sometimes one wallet pools many addresses, and sometimes several wallets sit behind a single address. This page shows each case, then lets you try the permutations.

Two ideas are worth keeping apart as you read. An **on-chain wallet** is a keypair and the address derived from it, and it works on every network that shares its key derivation. An **Anchorage Digital wallet** is a container for balances on one network inside one vault, with its own `walletId`. For where wallets sit in the wider structure, see [Account hierarchy](/knowledge-base/platform/developers/account-hierarchy).

## How a wallet ID maps to addresses

The `walletId` is the identifier your integration operates on. Withdrawals, balances, and calls to `GET /v2/wallets` all name a wallet, never an address. How many on-chain addresses sit underneath it depends on the network's transaction model, which [Account hierarchy](/knowledge-base/platform/developers/account-hierarchy) covers in detail.

<WalletAddressMap />

On account-based networks the wallet and the address are interchangeable in practice, which is why the distinction is easy to miss. On UTXO networks they clearly aren't: a transfer pulls from multiple source addresses automatically, and the unspent remainder returns to a new change address inside the same wallet.

## What one address can hold

A single on-chain address holds more than one type of asset. The network's native asset and every token issued on that network arrive at the same address and sit in the same wallet, each with its own balance.

<AddressAssetTypes />

Because the address is shared across the whole token layer, you can't add a second deposit address to an existing wallet on an account-based network. Create another wallet in the vault instead, and it comes with its own `walletId`.

## Two ways to map compatible networks

Compatible networks share a key derivation, so one keypair works across all of them. In the API, each network carries a `keyFamily`: an opaque identifier where two networks can share wallet private keys when their values match. Treat it as an equality comparison within a single response, and don't parse or cache the value.

Address sharing is available on EVM, SPL, and Tendermint networks. When you create wallets on more than one network in a family, you choose between two setups.

<CompatibleNetworkOptions />

The choice is made at creation: the selected network only, all compatible networks, or a subset you pick. See [Creating and managing wallets](/knowledge-base/platform/users/wallet-creation) for the flow, including how to extend an existing wallet's address onto more networks later.

<Note>
  Balances never cross networks on their own in either setup. Moving assets from one compatible network to another means bridging, not transferring.
</Note>

## Plan a configuration

Set a network, decide how many networks to cover, and pick an address strategy. The diagram redraws to show the wallets you'd create, their wallet IDs, and the addresses underneath them.

<WalletPlanner />

## What follows from the model

* The first wallet created for a network in a vault becomes that vault's default wallet, and the source of funds for external withdrawals, trade settlement, and holds executed by API.
* A generated address stays live on the blockchain and can't be deleted, so it keeps receiving. Addresses can be reused.
* Trusted destinations are per network. The same address on two networks needs two entries, and a withdrawal fails if the address is allowlisted on a different network than the one you send on. See [Trusted destinations](/knowledge-base/platform/developers/move-money/setup/trusted-destinations).
* On certain networks, creating one wallet also generates the wallets for all compatible networks and archives them. Archived wallets still receive deposits, but unarchive them before staking or withdrawing.
* A deposit that arrives on a compatible network where you have no wallet is still detected on the shared address. We run spam attribution and create the wallet if the deposit clears.
* Each asset carries an `availableBalance` and a `totalBalance` per wallet. See [Account hierarchy](/knowledge-base/platform/developers/account-hierarchy) for what each one includes.


## Related topics

- [Understanding wallets and addresses](/knowledge-base/platform/users/wallet-address-model.md)
- [On-chain interactions](/knowledge-base/platform/users/on-chain-interactions.md)
- [B2B2X accounts](/knowledge-base/platform/developers/b2b2x.md)
- [Crypto withdrawal](/knowledge-base/porto/developers/move-money/withdraw/crypto.md)
