> ## Documentation Index
> Fetch the complete documentation index at: https://base-a060aa97-docs-use-case-ia-overhaul.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Mint Supply

> Issue new stablecoin supply on Base as reserves grow, gated by a minter role and an optional supply cap.

export const StablecoinDemo = ({flow}) => {
  const sans = "'Base Sans','Inter Tight',Inter,system-ui,-apple-system,'Segoe UI',Roboto,sans-serif";
  const mono = "'Base Mono','Roboto Mono',ui-monospace,'SF Mono',Menlo,Consolas,monospace";
  const c = {
    bg: "var(--sd-bg)",
    panel: "var(--sd-panel)",
    border: "var(--sd-border)",
    console: "var(--sd-console)",
    text: "var(--sd-text)",
    body: "var(--sd-body)",
    muted: "var(--sd-muted)",
    dim: "var(--sd-dim)",
    accent: "var(--sd-accent)",
    accentContrast: "var(--sd-accent-contrast)",
    accentSoft: "var(--sd-accent-soft)",
    success: "var(--sd-success)",
    successSoft: "var(--sd-success-soft)",
    error: "var(--sd-error)"
  };
  const dot = {
    Issuer: "var(--sd-accent)",
    Alice: "#66c800",
    Bob: "#ffd12f",
    Merchant: "#3c8aff"
  };
  const ok = (name, detail) => ({
    kind: "ok",
    name,
    detail: detail || ""
  });
  const err = (name, detail) => ({
    kind: "err",
    name,
    detail: detail || ""
  });
  const nfo = (name, detail) => ({
    kind: "info",
    name,
    detail: detail || ""
  });
  const fmt = n => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  const glyph = {
    issue: <><circle cx="12" cy="12" r="9" /><path d="M12 8v8M8 12h8" /></>,
    mint: <path d="M12 19V5M5 12l7-7 7 7" />,
    burn: <path d="M12 3c2 3 5 4.5 5 8a5 5 0 0 1-10 0c0-1.6.8-2.6 1.4-3 .3 1.8 1.6 2 1.6.3 0-1.9-1-3.4 2-8.3z" />,
    restrict: <><rect x="5" y="11" width="14" height="9" rx="2" /><path d="M8 11V8a4 4 0 0 1 8 0v3" /></>,
    block: <><circle cx="12" cy="12" r="9" /><path d="M6 6l12 12" /></>,
    recover: <><path d="M4 12a8 8 0 1 0 2.3-5.7" /><path d="M4 4v4h4" /></>,
    pause: <><rect x="7" y="6" width="3.4" height="12" rx="1.2" /><rect x="13.6" y="6" width="3.4" height="12" rx="1.2" /></>,
    reconcile: <><path d="M7 3h10v18l-2.5-1.6L12 21l-2.5-1.6L7 21z" /><path d="M10 8h4M10 12h4" /></>
  };
  const Icon = ({k, size}) => <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">{glyph[k]}</svg>;
  const freshSim = () => ({
    balances: {},
    blocked: null
  });
  const FLOWS = {
    issue: {
      label: "Issue",
      title: "Issue a stablecoin in one call",
      readout: false,
      erc20: "On plain ERC-20 you write, deploy, and audit a token contract.",
      steps: [{
        text: "Create a fiat-backed token. Name, currency, and admin are set at creation.",
        action: "Create token",
        run: () => ({
          entries: [ok("createB20", "stablecoin · aUSD · 0xB20…a1c9"), nfo("initCalls", "grantRole(MINT_ROLE, Issuer)")],
          caption: "One factory call, with no contract to write or audit."
        })
      }, {
        text: "It's live and fully ERC-20 compatible.",
        action: "Confirm",
        run: () => ({
          entries: [nfo("currency()", '"USD"'), nfo("decimals()", "6")],
          caption: "Every wallet and exchange that speaks ERC-20 works with it unchanged."
        })
      }]
    },
    mint: {
      label: "Mint",
      title: "Mint as reserves grow",
      readout: true,
      erc20: "On plain ERC-20, mint permissions and supply caps are custom code.",
      steps: [{
        text: "1,000 in fiat lands in reserves. Mint matching supply.",
        action: "Mint 1,000",
        run: s => {
          s.balances.Alice = (s.balances.Alice || 0) + 1000;
          return {
            entries: [ok("Transfer", "0x0 → Alice · 1,000")]
          };
        }
      }, {
        text: "Cap supply so circulation can't exceed reserves.",
        action: "Cap at 1,200",
        run: () => ({
          entries: [ok("SupplyCapUpdated", "cap 1,200")]
        })
      }, {
        text: "A mint past the cap is rejected by the protocol.",
        action: "Try minting 500",
        run: () => ({
          entries: [err("SupplyCapExceeded", "cap 1,200 · supply 1,000")],
          caption: "Supply can never exceed the cap you set."
        })
      }]
    },
    burn: {
      label: "Burn",
      title: "Burn on redemption",
      readout: true,
      erc20: "On plain ERC-20, redemption bookkeeping is custom code.",
      steps: [{
        text: "Alice holds 1,000 aUSD.",
        action: "Fund Alice",
        run: s => {
          s.balances.Alice = 1000;
          return {
            entries: [ok("Transfer", "0x0 → Alice · 1,000")]
          };
        }
      }, {
        text: "Alice redeems 400 for fiat and returns the tokens.",
        action: "Return 400",
        run: s => {
          s.balances.Alice -= 400;
          s.balances.Issuer = (s.balances.Issuer || 0) + 400;
          return {
            entries: [ok("Transfer", "Alice → Issuer · 400")]
          };
        }
      }, {
        text: "Retire the returned tokens so supply matches reserves.",
        action: "Burn 400",
        run: s => {
          s.balances.Issuer -= 400;
          return {
            entries: [ok("Transfer", "Issuer → 0x0 · 400"), ok("Memo", '"redeem-8842"')],
            caption: "The burned tokens leave circulation for good."
          };
        }
      }]
    },
    restrict: {
      label: "Restrict",
      title: "Only approved accounts can hold it",
      readout: true,
      erc20: "On plain ERC-20, KYC gating is a custom transfer hook you build and audit.",
      steps: [{
        text: "Turn on your KYC allowlist. Approve Alice and your merchant.",
        action: "Enable allowlist",
        run: () => ({
          entries: [ok("PolicyCreated", "#2 · ALLOWLIST"), ok("updateAllowlist", "allow Alice, Merchant"), ok("PolicyUpdated", "TRANSFER_SENDER, TRANSFER_RECEIVER → #2")],
          caption: "Every account is denied until you approve it."
        })
      }, {
        text: "Approved accounts transact normally.",
        action: "Alice pays merchant",
        run: s => {
          s.balances.Alice = 100 - 40;
          s.balances.Merchant = 40;
          return {
            entries: [ok("Transfer", "0x0 → Alice · 100"), ok("Transfer", "Alice → Merchant · 40")]
          };
        }
      }, {
        text: "An account you haven't approved is turned away.",
        action: "Try paying Bob",
        run: () => ({
          entries: [err("PolicyForbids", "TRANSFER_RECEIVER · Bob")],
          caption: "Bob isn't on the allowlist, so the transfer can't land."
        })
      }]
    },
    block: {
      label: "Block",
      title: "Block one address, leave everyone else",
      readout: true,
      erc20: "On plain ERC-20, a blocklist is custom contract code.",
      steps: [{
        text: "Bob holds 50 aUSD.",
        action: "Mint to Bob",
        run: s => {
          s.balances.Bob = 50;
          return {
            entries: [ok("Transfer", "0x0 → Bob · 50")]
          };
        }
      }, {
        text: "A compliance hold comes in for Bob's address.",
        action: "Block address",
        run: s => {
          s.blocked = "Bob";
          return {
            entries: [ok("updateBlocklist", "add Bob"), ok("PolicyUpdated", "TRANSFER_SENDER → blocklist")],
            caption: "Only Bob is affected. The token keeps trading for everyone else."
          };
        }
      }, {
        text: "Bob can no longer move funds.",
        action: "Bob tries to pay",
        run: () => ({
          entries: [err("PolicyForbids", "TRANSFER_SENDER · Bob")],
          caption: "Blocked by the protocol, not by custom contract code."
        })
      }, {
        text: "When the hold clears, unblock the address.",
        action: "Unblock",
        run: s => {
          s.blocked = null;
          return {
            entries: [ok("updateBlocklist", "remove Bob")],
            caption: "Bob can transact again."
          };
        }
      }]
    },
    recover: {
      label: "Recover",
      title: "Recover funds from a blocked account",
      readout: true,
      erc20: "On plain ERC-20, there's no safe recovery path without custom code.",
      steps: [{
        text: "Bob's address is blocked and holds 50 aUSD.",
        action: "Set up",
        run: s => {
          s.balances.Bob = 50;
          s.blocked = "Bob";
          return {
            entries: [ok("Transfer", "0x0 → Bob · 50"), ok("updateBlocklist", "add Bob")]
          };
        }
      }, {
        text: "A holder lost their keys. Reclaim the balance.",
        action: "Reclaim funds",
        run: s => {
          s.balances.Bob = 0;
          return {
            entries: [ok("Transfer", "Bob → 0x0 · 50 (recovered)")],
            caption: "Recovery only works on an account that's already blocked."
          };
        }
      }, {
        text: "Reissue to the holder's new address.",
        action: "Reissue",
        run: s => {
          s.balances.Alice = (s.balances.Alice || 0) + 50;
          return {
            entries: [ok("Transfer", "0x0 → Alice · 50")],
            caption: "Circulating supply is unchanged: reclaimed, then reissued."
          };
        }
      }]
    },
    pause: {
      label: "Pause",
      title: "Halt activity in an incident",
      readout: true,
      erc20: "On plain ERC-20, a pause switch is custom code, usually all-or-nothing.",
      steps: [{
        text: "Alice holds 100 aUSD. Everything is running normally.",
        action: "Fund Alice",
        run: s => {
          s.balances.Alice = 100;
          return {
            entries: [ok("Transfer", "0x0 → Alice · 100")]
          };
        }
      }, {
        text: "An incident hits. Halt transfers instantly.",
        action: "Pause transfers",
        run: () => ({
          entries: [ok("Paused", "TRANSFER")],
          caption: "Only transfers stop. Pausing is granular."
        })
      }, {
        text: "No one can move funds while transfers are paused.",
        action: "Try a transfer",
        run: () => ({
          entries: [err("EnforcedPause", "TRANSFER is paused")]
        })
      }, {
        text: "Resume once the incident is resolved.",
        action: "Resume",
        run: () => ({
          entries: [ok("Unpaused", "TRANSFER")],
          caption: "Transfers work again."
        })
      }]
    },
    reconcile: {
      label: "Reconcile",
      title: "Match a payment to an order",
      readout: false,
      erc20: "On plain ERC-20, transfers carry no reference, so you run a deposit address per customer.",
      steps: [{
        text: "Alice pays your processor 25 aUSD, tagged with the invoice.",
        action: "Pay with memo",
        run: () => ({
          entries: [ok("Transfer", "Alice → Merchant · 25"), ok("Memo", '"invoice-8842"')],
          caption: "One transaction carries both the payment and the reference."
        })
      }, {
        text: "The back office matches the payment to the order.",
        action: "Match payment",
        run: () => ({
          entries: [nfo("query", "Transfer at (txHash, Memo.logIndex − 1)"), nfo("matched", '"invoice-8842" → 25 aUSD ✓')],
          caption: "Reconciliation is one log query, not a deposit address per customer."
        })
      }]
    }
  };
  const order = ["issue", "mint", "burn", "restrict", "block", "recover", "pause", "reconcile"];
  const pinned = flow && FLOWS[flow] ? flow : null;
  const [active, setActive] = useState(pinned || "issue");
  const [sim, setSim] = useState(freshSim);
  const [results, setResults] = useState([]);
  const f = FLOWS[active] || FLOWS.issue;
  const stepIndex = results.length;
  const done = stepIndex >= f.steps.length;
  const pct = Math.round(stepIndex / f.steps.length * 100);
  const select = k => {
    setActive(k);
    setSim(freshSim());
    setResults([]);
  };
  const reset = () => {
    setSim(freshSim());
    setResults([]);
  };
  const runStep = () => {
    if (done) return;
    const s = {
      balances: {
        ...sim.balances
      },
      blocked: sim.blocked
    };
    const out = f.steps[stepIndex].run(s) || ({
      entries: []
    });
    setSim(s);
    setResults(r => [...r, out]);
  };
  const holders = Object.keys(sim.balances);
  return <div className="sd-card" style={{
    margin: "22px 0",
    borderRadius: 14,
    border: `1px solid ${c.border}`,
    background: c.bg,
    overflow: "hidden",
    boxShadow: "var(--sd-shadow)"
  }}>
      <style>{`
        .sd-card{
          --sd-bg:#ffffff; --sd-panel:#f5f6f8; --sd-console:#f7f8fa; --sd-border:#e2e5ea;
          --sd-text:#0a0b0d; --sd-body:#32353d; --sd-muted:#5b616e; --sd-dim:#8a909c;
          --sd-accent:#0000ff; --sd-accent-contrast:#ffffff; --sd-accent-soft:rgba(0,0,255,.08);
          --sd-success:#1a9d37; --sd-success-soft:rgba(26,157,55,.12); --sd-error:#e5402a;
          --sd-shadow:0 1px 2px rgba(10,11,13,.05), 0 14px 34px -20px rgba(10,11,13,.28);
        }
        html.dark .sd-card, [data-theme="dark"] .sd-card{
          --sd-bg:#0d0e11; --sd-panel:rgba(255,255,255,.045); --sd-console:rgba(255,255,255,.03); --sd-border:#2b2e36;
          --sd-text:#ffffff; --sd-body:#dee1e7; --sd-muted:#b1b7c3; --sd-dim:#7b828f;
          --sd-accent:#578BFA; --sd-accent-contrast:#0a0b0d; --sd-accent-soft:rgba(87,139,250,.16);
          --sd-success:#66c800; --sd-success-soft:rgba(102,200,0,.16); --sd-error:#fc655a;
          --sd-shadow:0 1px 2px rgba(0,0,0,.4), 0 18px 40px -22px rgba(0,0,0,.7);
        }
        @keyframes sd-in{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
        .sd-res{animation:sd-in .28s ease both}
        .sd-line{animation:sd-in .28s ease both}
        .sd-prog{transition:width .35s cubic-bezier(.4,0,.2,1)}
        .sd-pill{font-family:${sans};font-size:12px;font-weight:500;border-radius:999px;padding:5px 11px 5px 9px;cursor:pointer;transition:all .15s ease;white-space:nowrap;display:inline-flex;align-items:center;gap:5px;color:var(--sd-muted);background:transparent;border:1px solid var(--sd-border)}
        .sd-pill:hover{color:var(--sd-text);border-color:var(--sd-dim)}
        .sd-pill-on{color:var(--sd-accent-contrast);background:var(--sd-accent);border-color:var(--sd-accent)}
        .sd-btn{font-family:${sans};font-size:12.5px;font-weight:600;border-radius:8px;padding:7px 13px;cursor:pointer;transition:all .15s ease;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;color:var(--sd-accent-contrast);background:var(--sd-accent);border:1px solid var(--sd-accent);box-shadow:0 1px 2px rgba(0,0,0,.12)}
        .sd-btn:hover{filter:brightness(1.12);transform:translateY(-1px)}
        .sd-btn:disabled{color:var(--sd-dim);background:transparent;border:1px dashed var(--sd-border);cursor:default;filter:none;transform:none;box-shadow:none;font-weight:500}
        .sd-reset{font-family:${sans};font-size:11px;color:var(--sd-dim);background:transparent;border:none;cursor:pointer;padding:2px 6px;border-radius:6px}
        .sd-reset:hover{color:var(--sd-body);background:var(--sd-panel)}
      `}</style>

      {}
      <div style={{
    height: 3,
    background: c.border
  }}>
        <div className="sd-prog" style={{
    height: "100%",
    width: `${pct}%`,
    background: done ? c.success : c.accent
  }} />
      </div>

      {}
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: 11,
    padding: "12px 16px",
    background: c.panel,
    borderBottom: `1px solid ${c.border}`
  }}>
        <span style={{
    width: 30,
    height: 30,
    borderRadius: 9,
    flexShrink: 0,
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    color: c.accent,
    background: c.accentSoft
  }}>
          <Icon k={active} size={16} />
        </span>
        <div style={{
    display: "flex",
    flexDirection: "column",
    gap: 1,
    minWidth: 0
  }}>
          <span style={{
    fontFamily: sans,
    fontSize: 9.5,
    fontWeight: 600,
    letterSpacing: "0.9px",
    color: c.dim,
    textTransform: "uppercase"
  }}>Interactive demo · simulated</span>
          <span style={{
    fontFamily: sans,
    fontSize: 13.5,
    fontWeight: 600,
    letterSpacing: "-0.01em",
    color: c.text
  }}>{f.title}</span>
        </div>
        <div style={{
    flex: 1
  }} />
        <span style={{
    fontFamily: mono,
    fontSize: 10.5,
    color: c.dim,
    whiteSpace: "nowrap"
  }}>{Math.min(stepIndex, f.steps.length)}/{f.steps.length}</span>
        {results.length > 0 && <button className="sd-reset" onClick={reset}>reset</button>}
      </div>

      {}
      {!pinned && <div style={{
    display: "flex",
    flexWrap: "wrap",
    gap: 6,
    padding: "11px 16px",
    borderBottom: `1px solid ${c.border}`
  }}>
          {order.map(k => <button key={k} className={k === active ? "sd-pill sd-pill-on" : "sd-pill"} onClick={() => select(k)}>
              <Icon k={k} size={13} />{FLOWS[k].label}
            </button>)}
        </div>}

      {}
      <div style={{
    padding: "14px 16px 6px"
  }}>
        {f.steps.map((step, i) => {
    const state = i < stepIndex ? "done" : i === stepIndex ? "now" : "future";
    const res = results[i];
    const last = i === f.steps.length - 1;
    return <div key={i} style={{
      display: "flex",
      gap: 12
    }}>
              {}
              <div style={{
      display: "flex",
      flexDirection: "column",
      alignItems: "center",
      width: 22,
      flexShrink: 0
    }}>
                <span style={{
      width: 22,
      height: 22,
      borderRadius: "50%",
      flexShrink: 0,
      display: "inline-flex",
      alignItems: "center",
      justifyContent: "center",
      fontFamily: sans,
      fontSize: 11,
      fontWeight: 600,
      color: state === "done" ? c.accentContrast : state === "now" ? c.accentContrast : c.dim,
      border: `1.5px solid ${state === "future" ? c.border : c.accent}`,
      background: state === "done" ? c.success : state === "now" ? c.accent : "transparent",
      borderColor: state === "done" ? c.success : state === "future" ? c.border : c.accent,
      transition: "all .2s ease"
    }}>
                  {state === "done" ? <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke={c.accentContrast} strokeWidth="3.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg> : i + 1}
                </span>
                {!last && <div style={{
      flex: 1,
      width: 2,
      minHeight: 16,
      marginTop: 4,
      background: i < stepIndex ? c.accent : c.border,
      transition: "background .3s ease"
    }} />}
              </div>

              {}
              <div style={{
      flex: 1,
      paddingBottom: last ? 8 : 16,
      minWidth: 0
    }}>
                <div style={{
      display: "flex",
      alignItems: "center",
      gap: 12,
      minHeight: 22
    }}>
                  <span style={{
      flex: 1,
      fontFamily: sans,
      fontSize: 13,
      lineHeight: 1.45,
      color: state === "future" ? c.dim : state === "now" ? c.text : c.body,
      fontWeight: state === "now" ? 600 : 400
    }}>{step.text}</span>
                  {state !== "done" && <button className="sd-btn" onClick={state === "now" ? runStep : undefined} disabled={state !== "now"}>
                      {step.action}
                      {state === "now" && <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>}
                    </button>}
                </div>
                {res && <div className="sd-res" style={{
      marginTop: 9,
      background: c.console,
      border: `1px solid ${c.border}`,
      borderRadius: 8,
      padding: "8px 10px",
      display: "grid",
      gap: 4
    }}>
                    {res.entries.map((e, j) => <div key={j} className="sd-line" style={{
      display: "flex",
      alignItems: "flex-start",
      gap: 7,
      animationDelay: `${j * 60}ms`
    }}>
                        <span style={{
      flexShrink: 0,
      width: 12,
      marginTop: 2
    }}>
                          {e.kind === "ok" && <svg viewBox="0 0 24 24" width="11" height="11" fill="none" style={{
      stroke: c.success
    }} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>}
                          {e.kind === "err" && <svg viewBox="0 0 24 24" width="11" height="11" fill="none" style={{
      stroke: c.error
    }} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18M6 6l12 12" /></svg>}
                          {e.kind === "info" && <span style={{
      display: "inline-block",
      width: 5,
      height: 5,
      borderRadius: "50%",
      background: c.dim,
      marginLeft: 3,
      marginTop: 3
    }} />}
                        </span>
                        <span style={{
      fontFamily: mono,
      fontSize: 11,
      lineHeight: 1.5
    }}>
                          <span style={{
      color: e.kind === "err" ? c.error : e.kind === "info" ? c.muted : c.body,
      fontWeight: e.kind === "info" ? 400 : 600
    }}>{e.name}</span>
                          {e.detail && <span style={{
      color: c.dim
    }}> · {e.detail}</span>}
                        </span>
                      </div>)}
                    {res.caption && <div style={{
      fontFamily: sans,
      fontSize: 11.5,
      color: c.muted,
      lineHeight: 1.45,
      marginTop: 3,
      borderLeft: `2px solid ${c.accent}`,
      paddingLeft: 8
    }}>{res.caption}</div>}
                  </div>}
              </div>
            </div>;
  })}

        {}
        {f.readout && holders.length > 0 && <div style={{
    marginTop: 4,
    marginBottom: 10,
    padding: "9px 12px",
    background: c.panel,
    border: `1px solid ${c.border}`,
    borderRadius: 10
  }}>
            <div style={{
    fontFamily: sans,
    fontSize: 9.5,
    fontWeight: 600,
    letterSpacing: "0.9px",
    color: c.dim,
    textTransform: "uppercase",
    marginBottom: 6
  }}>Balances</div>
            <div style={{
    display: "flex",
    flexWrap: "wrap",
    gap: 7
  }}>
              {holders.map(a => <span key={a} style={{
    fontFamily: sans,
    fontSize: 11.5,
    color: c.body,
    display: "inline-flex",
    alignItems: "center",
    gap: 6,
    padding: "3px 9px",
    borderRadius: 999,
    background: c.bg,
    border: `1px solid ${c.border}`
  }}>
                  <span style={{
    width: 8,
    height: 8,
    borderRadius: "50%",
    background: dot[a] || c.dim,
    display: "inline-block"
  }} />
                  {a}<span style={{
    fontFamily: mono,
    color: c.text,
    fontWeight: 600
  }}>{fmt(sim.balances[a] || 0)}</span>
                  {sim.blocked === a && <span style={{
    fontFamily: sans,
    fontSize: 9.5,
    fontWeight: 600,
    letterSpacing: "0.4px",
    textTransform: "uppercase",
    color: c.error,
    border: `1px solid ${c.error}`,
    borderRadius: 5,
    padding: "0px 5px"
  }}>blocked</span>}
                </span>)}
            </div>
          </div>}
      </div>

      {}
      <div style={{
    padding: "10px 16px",
    background: c.panel,
    borderTop: `1px solid ${c.border}`,
    display: "flex",
    alignItems: "center",
    gap: 10
  }}>
        <span style={{
    fontFamily: sans,
    fontSize: 11,
    color: c.dim,
    lineHeight: 1.4
  }}>{f.erc20}</span>
        <div style={{
    flex: 1
  }} />
        {done && <span style={{
    fontFamily: sans,
    fontSize: 10.5,
    fontWeight: 600,
    color: c.success,
    background: c.successSoft,
    borderRadius: 999,
    padding: "3px 10px",
    whiteSpace: "nowrap",
    display: "inline-flex",
    alignItems: "center",
    gap: 5
  }}>
            <svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke={c.success} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
            Flow complete
          </span>}
      </div>
    </div>;
};

When fiat lands in reserves, mint matching supply. Minting is gated by `MINT_ROLE`, and an optional supply cap keeps circulation from exceeding your reserves.

#### Demo

<StablecoinDemo flow="mint" />

## Mint and cap

```bash Terminal theme={null}
# Mint 1,000 MUSD (6 decimals) to a holder.
base-cast send $TOKEN_ADDRESS "mint(address,uint256)" $HOLDER 1000000000 \
  --rpc-url $RPC_URL --private-key $MINTER_KEY

# Cap total supply. A mint past the cap reverts with SupplyCapExceeded.
base-cast send $TOKEN_ADDRESS "updateSupplyCap(uint256)" 10000000000000 \
  --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```

Use `mintWithMemo` to tag a mint with the reserve deposit it backs. See [Reconcile with memos](/build-on-base/issue-stablecoins/reconcile-with-memos).

## See also

* [Burn supply](/build-on-base/issue-stablecoins/burn-supply)
* [Mint](/base-chain/specs/upgrades/beryl/b20#mint) and [Supply cap](/base-chain/specs/upgrades/beryl/b20#supply-cap) in the B20 standard
