> ## 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.

# Integrate Lending

> Let users supply USDC directly to Morpho, Moonwell, or Aave lending markets on Base.

export const DeFiDemo = ({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 = {
    blue: "#0000ff",
    onBlue: "#ffffff",
    cerulean: "#3c8aff",
    ink: "#0a0b0d",
    body: "#32353d",
    sec: "#5b616e",
    sub: "#717886",
    border: "#dee1e7",
    panel: "#eef0f3",
    white: "#ffffff",
    success: "#66c800",
    lime: "#b6f569",
    error: "#fc401f",
    warn: "#ffd12f",
    blueSoft: "rgba(0,0,255,.06)",
    successSoft: "rgba(102,200,0,.12)",
    errorSoft: "rgba(252,64,31,.10)"
  };
  const NETWORK = "Base Mainnet";
  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 M = v => ({
    v,
    mono: true
  });
  const freshSim = () => ({
    metrics: []
  });
  const FLOWS = {
    lend: {
      label: "Lend",
      title: "Supply assets to a lending market",
      readout: true,
      footer: "Illustrative only · rates and liquidity vary by market.",
      steps: [{
        stage: "Load",
        action: "Load wallet",
        text: "A user has 1,000 USDC available in their wallet.",
        summary: [["Operation", "Load wallet"], ["Asset", M("USDC")], ["Amount", M("1,000 USDC")], ["Network", NETWORK]],
        run: s => {
          s.metrics = [{
            label: "Wallet",
            value: "1,000 USDC"
          }, {
            label: "Supplied",
            value: "0 USDC"
          }];
          return {
            entries: [nfo("wallet balance", "1,000 USDC")]
          };
        }
      }, {
        stage: "Supply",
        action: "Supply USDC",
        text: "Approve the market and supply the USDC from the user's wallet.",
        summary: [["Operation", "Supply"], ["Market", "USDC lending"], ["Amount", M("1,000 USDC")], ["Supply APY", M("4.2%")], ["Network", NETWORK]],
        run: s => {
          s.metrics = [{
            label: "Wallet",
            value: "0 USDC"
          }, {
            label: "Supplied",
            value: "1,000 USDC"
          }, {
            label: "Supply APY",
            value: "4.2% variable"
          }];
          return {
            entries: [ok("approve", "1,000 USDC"), ok("supply", "1,000 USDC")],
            caption: "The wallet now owns a direct protocol position."
          };
        }
      }, {
        stage: "Accrue",
        action: "Accrue 30 days",
        text: "The supplied position accrues illustrative variable interest.",
        summary: [["Operation", "Accrue interest"], ["Period", "30 days"], ["Supply APY", M("4.2%")], ["Balance", M("1,003.45 USDC")]],
        run: s => {
          s.metrics = [{
            label: "Wallet",
            value: "0 USDC"
          }, {
            label: "Supplied",
            value: "1,003.45 USDC"
          }, {
            label: "Supply APY",
            value: "4.2% variable"
          }];
          return {
            entries: [ok("position updated", "+3.45 USDC")],
            caption: "Actual rates change with market utilization."
          };
        }
      }, {
        stage: "Withdraw",
        action: "Withdraw",
        text: "Withdraw the available position back to the user's wallet.",
        summary: [["Operation", "Withdraw"], ["Amount", M("1,003.45 USDC")], ["To", "Wallet"], ["Network", NETWORK]],
        run: s => {
          s.metrics = [{
            label: "Wallet",
            value: "1,003.45 USDC"
          }, {
            label: "Supplied",
            value: "0 USDC"
          }];
          return {
            entries: [ok("withdraw", "1,003.45 USDC")],
            caption: "Withdrawals depend on available market liquidity."
          };
        }
      }]
    },
    borrow: {
      label: "Borrow",
      title: "Borrow against supplied collateral",
      readout: true,
      footer: "Illustrative only · liquidation parameters differ by protocol and market.",
      steps: [{
        stage: "Collateral",
        action: "Supply collateral",
        text: "A user supplies 2 WETH as collateral at an illustrative $2,500 price.",
        summary: [["Operation", "Supply collateral"], ["Collateral", M("2 WETH")], ["Value", M("$5,000")], ["Network", NETWORK]],
        run: s => {
          s.metrics = [{
            label: "Collateral",
            value: "2 WETH · $5,000"
          }, {
            label: "Debt",
            value: "0 USDC"
          }, {
            label: "Health factor",
            value: "—"
          }];
          return {
            entries: [ok("supply collateral", "2 WETH"), ok("collateral enabled", "WETH")],
            caption: "The collateral remains exposed to market price changes."
          };
        }
      }, {
        stage: "Borrow",
        action: "Borrow USDC",
        text: "Borrow 2,000 USDC against the collateral.",
        summary: [["Operation", "Borrow"], ["Asset", M("USDC")], ["Amount", M("2,000 USDC")], ["Health factor", M("2.00")], ["Network", NETWORK]],
        run: s => {
          s.metrics = [{
            label: "Collateral",
            value: "2 WETH · $5,000"
          }, {
            label: "Debt",
            value: "2,000 USDC"
          }, {
            label: "Health factor",
            value: "2.00",
            tone: "ok"
          }];
          return {
            entries: [ok("borrow", "2,000 USDC"), nfo("health factor", "2.00")],
            caption: "A higher health factor provides more room before liquidation."
          };
        }
      }, {
        stage: "Price drop",
        action: "Simulate price drop",
        text: "WETH falls to an illustrative $1,500 while the debt remains unchanged.",
        summary: [["Operation", "Price update"], ["Collateral", M("2 WETH · $3,000")], ["Debt", M("2,000 USDC")], ["Health factor", M("1.20")]],
        run: s => {
          s.metrics = [{
            label: "Collateral",
            value: "2 WETH · $3,000"
          }, {
            label: "Debt",
            value: "2,000 USDC"
          }, {
            label: "Health factor",
            value: "1.20",
            tone: "warn"
          }];
          return {
            entries: [err("risk increased", "health factor 2.00 → 1.20")],
            caption: "At or below the protocol's liquidation threshold, collateral can be sold to repay debt."
          };
        }
      }]
    },
    earn: {
      label: "Earn",
      title: "Embed a vault-based earn product",
      readout: true,
      footer: "Illustrative only · vault yield is variable and not guaranteed.",
      steps: [{
        stage: "Select",
        action: "Select vault",
        text: "A user has 1,000 USDC and chooses a curated vault in your app.",
        summary: [["Operation", "Select vault"], ["Vault", "USDC yield"], ["Asset", M("USDC")], ["Network", NETWORK]],
        run: s => {
          s.metrics = [{
            label: "Wallet",
            value: "1,000 USDC"
          }, {
            label: "Vault shares",
            value: "0"
          }, {
            label: "Redeemable",
            value: "0 USDC"
          }];
          return {
            entries: [nfo("vault selected", "USDC · variable yield")],
            caption: "The vault abstracts the underlying market allocation."
          };
        }
      }, {
        stage: "Deposit",
        action: "Deposit USDC",
        text: "Deposit once and receive shares that represent the vault position.",
        summary: [["Operation", "Deposit"], ["Amount", M("1,000 USDC")], ["Vault shares", M("1,000")], ["Share price", M("$1.00")], ["Network", NETWORK]],
        run: s => {
          s.metrics = [{
            label: "Wallet",
            value: "0 USDC"
          }, {
            label: "Vault shares",
            value: "1,000"
          }, {
            label: "Share price",
            value: "$1.00"
          }, {
            label: "Redeemable",
            value: "1,000 USDC"
          }];
          return {
            entries: [ok("approve", "1,000 USDC"), ok("deposit", "1,000 USDC → 1,000 shares")],
            caption: "The user holds vault shares instead of managing each market position."
          };
        }
      }, {
        stage: "Accrue",
        action: "Accrue value",
        text: "As the vault earns, each share becomes redeemable for more USDC.",
        summary: [["Operation", "Accrue yield"], ["Vault shares", M("1,000")], ["Share price", M("$1.01")], ["Redeemable", M("1,010 USDC")]],
        run: s => {
          s.metrics = [{
            label: "Wallet",
            value: "0 USDC"
          }, {
            label: "Vault shares",
            value: "1,000"
          }, {
            label: "Share price",
            value: "$1.01"
          }, {
            label: "Redeemable",
            value: "1,010 USDC",
            tone: "ok"
          }];
          return {
            entries: [ok("share value updated", "$1.00 → $1.01"), nfo("redeemable assets", "1,010 USDC")],
            caption: "Actual vault performance can rise or fall and depends on its strategy."
          };
        }
      }]
    }
  };
  const order = ["lend", "borrow", "earn"];
  const pinned = flow ? FLOWS[flow] ? flow : order[0] : null;
  const [active, setActive] = useState(pinned || "lend");
  const [sim, setSim] = useState(freshSim);
  const [results, setResults] = useState([]);
  const f = FLOWS[active] || FLOWS.lend;
  const stepIndex = results.length;
  const done = stepIndex >= f.steps.length;
  const cur = done ? f.steps[f.steps.length - 1] : f.steps[stepIndex];
  const select = k => {
    setActive(k);
    setSim(freshSim());
    setResults([]);
  };
  const reset = () => {
    setSim(freshSim());
    setResults([]);
  };
  const runStep = () => {
    if (done) return;
    const s = {
      metrics: sim.metrics.map(metric => ({
        ...metric
      }))
    };
    const out = f.steps[stepIndex].run(s) || ({
      entries: []
    });
    setSim(s);
    setResults(r => [...r, out]);
  };
  const back = () => {
    const n = results.length - 1;
    if (n < 0) return;
    let s = freshSim();
    for (let i = 0; i < n; i++) f.steps[i].run(s);
    setSim(s);
    setResults(r => r.slice(0, -1));
  };
  const pad = n => String(n).padStart(2, "0");
  const ts = n => {
    const t = 42 * 60 + 11 + n;
    return `10:${pad(Math.floor(t / 60) % 60)}:${pad(t % 60)}`;
  };
  const logRows = [];
  let sec = 0;
  results.forEach(res => {
    (res.entries || []).forEach(e => {
      logRows.push({
        t: ts(sec++),
        level: e.kind === "err" ? "ERROR" : e.kind === "info" ? "INFO" : "EVENT",
        name: e.name,
        detail: e.detail,
        kind: e.kind
      });
    });
  });
  f.steps.slice(stepIndex).forEach(st => {
    logRows.push({
      t: ts(sec++),
      level: "PENDING",
      name: st.action,
      detail: "",
      kind: "pending"
    });
  });
  const StatusTag = ({state}) => {
    const map = {
      done: [C.success, "Complete"],
      now: [C.blue, "In progress"],
      future: [C.sub, "Pending"]
    };
    const [col, txt] = map[state];
    return <span style={{
      fontFamily: sans,
      fontSize: 11,
      fontWeight: 600,
      color: col
    }}>{txt}</span>;
  };
  const levelColor = {
    EVENT: C.blue,
    INFO: C.sec,
    ERROR: C.error,
    PENDING: C.sub
  };
  return <div className="wf" style={{
    margin: "22px 0",
    maxWidth: 760,
    borderRadius: 8,
    border: `1px solid ${C.border}`,
    background: C.white,
    overflow: "hidden",
    boxShadow: "0 1px 2px rgba(10,11,13,.04)"
  }}>
      <style>{`
        .wf, .wf * { box-sizing: border-box; }
        .wf-nav { display: flex; gap: 20px; }
        .wf-split { display: grid; grid-template-columns: 43% 57%; }
        .wf-rail { border-right: 1px solid ${C.border}; }
        @keyframes wf-in { from { opacity: 0; transform: translateY(3px);} to { opacity: 1; transform: none; } }
        .wf-anim { animation: wf-in .26s ease both; }
        .wf-btn { font-family: ${sans}; font-size: 13px; font-weight: 600; border-radius: 6px; padding: 10px 14px; cursor: pointer; transition: filter .15s ease; border: 1px solid ${C.blue}; background: ${C.blue}; color: ${C.onBlue}; width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 7px; }
        .wf-btn:hover { filter: brightness(1.1); }
        .wf-btn:disabled { background: ${C.panel}; border-color: ${C.border}; color: ${C.sub}; cursor: default; filter: none; }
        .wf-btn2 { font-family: ${sans}; font-size: 13px; font-weight: 600; border-radius: 6px; padding: 10px 14px; cursor: pointer; background: ${C.white}; border: 1px solid ${C.border}; color: ${C.body}; width: 100%; transition: background .15s ease; }
        .wf-btn2:hover { background: ${C.panel}; }
        .wf-pill { font-family: ${sans}; font-size: 12px; font-weight: 500; border-radius: 6px; padding: 5px 10px; cursor: pointer; white-space: nowrap; color: ${C.sec}; background: ${C.white}; border: 1px solid ${C.border}; transition: all .12s ease; }
        .wf-pill:hover { color: ${C.ink}; border-color: ${C.sub}; }
        .wf-pill-on { color: ${C.onBlue}; background: ${C.blue}; border-color: ${C.blue}; }
        .wf-stage { font-family: ${sans}; font-size: 12.5px; white-space: nowrap; padding: 11px 2px; border-bottom: 2px solid transparent; display: inline-flex; align-items: center; gap: 7px; }
        @media (max-width: 640px) {
          .wf-split { grid-template-columns: 1fr; }
          .wf-rail { border-right: none; border-bottom: 1px solid ${C.border}; }
          .wf-nav { display: none; }
          .wf-stages { overflow-x: auto; }
        }
        @media (prefers-reduced-motion: reduce) { .wf-anim { animation: none !important; } }
      `}</style>

      {}
      {!pinned && <div style={{
    display: "flex",
    alignItems: "center",
    flexWrap: "wrap",
    gap: 6,
    padding: "10px 16px",
    borderBottom: `1px solid ${C.border}`,
    background: C.panel
  }}>
          <span style={{
    fontFamily: sans,
    fontSize: 10,
    fontWeight: 600,
    letterSpacing: ".6px",
    textTransform: "uppercase",
    color: C.sub,
    marginRight: 4
  }}>Scenario</span>
          {order.map(k => <button key={k} className={k === active ? "wf-pill wf-pill-on" : "wf-pill"} onClick={() => select(k)}>{FLOWS[k].label}</button>)}
        </div>}

      {}
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: 12,
    padding: "0 16px",
    borderBottom: `1px solid ${C.border}`,
    background: C.white
  }}>
        <div className="wf-stages" style={{
    display: "flex",
    gap: 22,
    flex: 1,
    minWidth: 0,
    overflowX: "auto"
  }}>
          {f.steps.map((st, i) => {
    const state = i < stepIndex ? "done" : i === stepIndex ? "now" : "future";
    const col = state === "future" ? C.sub : state === "now" ? C.blue : C.ink;
    return <span key={i} className="wf-stage" style={{
      color: col,
      borderBottomColor: state === "now" ? C.blue : "transparent",
      fontWeight: state === "now" ? 600 : 500
    }}>
                <span style={{
      fontFamily: mono,
      fontSize: 11,
      opacity: .7
    }}>{i + 1}</span>{st.stage}
                {state === "done" && <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke={C.success} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>}
              </span>;
  })}
        </div>
        <span style={{
    fontFamily: sans,
    fontSize: 10,
    fontWeight: 600,
    letterSpacing: ".6px",
    textTransform: "uppercase",
    color: C.sub,
    border: `1px solid ${C.border}`,
    borderRadius: 5,
    padding: "2px 6px",
    flexShrink: 0
  }}>Demo</span>
        {results.length > 0 && <button onClick={reset} title="Reset" style={{
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    width: 28,
    height: 24,
    borderRadius: 6,
    background: "transparent",
    border: `1px solid ${C.border}`,
    cursor: "pointer",
    color: C.sec,
    flexShrink: 0
  }}>
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7L21 8" /><path d="M21 3v5h-5" /></svg>
          </button>}
      </div>

      {}
      <div className="wf-split">
        {}
        <div className="wf-rail" style={{
    padding: "16px 16px 14px",
    background: C.white
  }}>
          {f.steps.map((st, i) => {
    const state = i < stepIndex ? "done" : i === stepIndex ? "now" : "future";
    const last = i === f.steps.length - 1;
    return <div key={i} style={{
      display: "flex",
      gap: 11
    }}>
                <div style={{
      display: "flex",
      flexDirection: "column",
      alignItems: "center",
      width: 24,
      flexShrink: 0
    }}>
                  <span style={{
      width: 24,
      height: 24,
      borderRadius: "50%",
      display: "inline-flex",
      alignItems: "center",
      justifyContent: "center",
      fontFamily: sans,
      fontSize: 11.5,
      fontWeight: 600,
      color: state === "future" ? C.sub : C.onBlue,
      background: state === "done" ? C.success : state === "now" ? C.blue : "transparent",
      border: `1.5px solid ${state === "done" ? C.success : state === "future" ? C.border : C.blue}`
    }}>
                    {state === "done" ? <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke={C.onBlue} 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: 22,
      marginTop: 4,
      marginBottom: 2,
      background: i < stepIndex ? C.blue : C.border
    }} />}
                </div>
                <div style={{
      flex: 1,
      paddingBottom: last ? 0 : 14,
      minWidth: 0
    }}>
                  <div style={{
      fontFamily: sans,
      fontSize: 13,
      fontWeight: state === "future" ? 500 : 600,
      color: state === "future" ? C.sub : C.ink,
      lineHeight: 1.3
    }}>{st.action}</div>
                  <div style={{
      marginTop: 2
    }}><StatusTag state={state} /></div>
                </div>
              </div>;
  })}

          {}
          {f.readout && sim.metrics.length > 0 && <div style={{
    marginTop: 14,
    paddingTop: 12,
    borderTop: `1px solid ${C.border}`
  }}>
              <div style={{
    fontFamily: sans,
    fontSize: 10,
    fontWeight: 600,
    letterSpacing: ".6px",
    textTransform: "uppercase",
    color: C.sub,
    marginBottom: 8
  }}>Illustrative position</div>
              <div style={{
    display: "grid",
    gap: 6
  }}>
                {sim.metrics.map(m => <div key={m.label} style={{
    display: "flex",
    alignItems: "center",
    gap: 8,
    fontFamily: sans,
    fontSize: 12.5,
    color: C.body
  }}>
                    <span style={{
    flex: 1
  }}>{m.label}</span>
                    <span style={{
    fontFamily: mono,
    fontSize: 12.5,
    fontWeight: 600,
    color: m.tone === "warn" ? C.error : m.tone === "ok" ? C.success : C.ink
  }}>{m.value}</span>
                  </div>)}
              </div>
            </div>}
        </div>

        {}
        <div style={{
    padding: "16px 18px",
    background: C.white,
    minWidth: 0
  }}>
          {done ? <div className="wf-anim">
              <div style={{
    display: "inline-flex",
    alignItems: "center",
    gap: 7,
    fontFamily: sans,
    fontSize: 12.5,
    fontWeight: 600,
    color: C.success,
    background: C.successSoft,
    borderRadius: 6,
    padding: "5px 10px"
  }}>
                <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke={C.success} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
                Flow complete
              </div>
              <div style={{
    fontFamily: sans,
    fontSize: 13.5,
    color: C.body,
    lineHeight: 1.5,
    margin: "12px 0 16px"
  }}>{f.title} — every step ran onchain in the simulation above.</div>
              <button className="wf-btn2" onClick={reset}>Run again</button>
            </div> : <div className="wf-anim" key={stepIndex}>
              <div style={{
    fontFamily: sans,
    fontSize: 15,
    fontWeight: 600,
    letterSpacing: "-0.01em",
    color: C.ink
  }}>{cur.action}</div>
              <div style={{
    fontFamily: sans,
    fontSize: 13,
    color: C.sec,
    lineHeight: 1.5,
    marginTop: 5
  }}>{cur.text}</div>

              <div style={{
    marginTop: 14,
    border: `1px solid ${C.border}`,
    borderRadius: 8,
    overflow: "hidden"
  }}>
                {cur.summary.map(([k, val], i) => {
    const isM = val && typeof val === "object" && val.mono;
    const v = isM ? val.v : val;
    return <div key={i} style={{
      display: "flex",
      alignItems: "center",
      justifyContent: "space-between",
      gap: 12,
      padding: "9px 12px",
      borderTop: i ? `1px solid ${C.border}` : "none"
    }}>
                      <span style={{
      fontFamily: sans,
      fontSize: 12.5,
      color: C.sec
    }}>{k}</span>
                      <span style={{
      fontFamily: isM ? mono : sans,
      fontSize: isM ? 12 : 12.5,
      fontWeight: isM ? 500 : 600,
      color: C.ink,
      textAlign: "right",
      wordBreak: "break-word"
    }}>
                        {k === "Network" && <span style={{
      display: "inline-block",
      width: 7,
      height: 7,
      borderRadius: "50%",
      background: C.cerulean,
      marginRight: 6
    }} />}
                        {v}
                      </span>
                    </div>;
  })}
              </div>

              <div style={{
    marginTop: 14,
    display: "grid",
    gap: 8
  }}>
                <button className="wf-btn" onClick={runStep}>
                  {cur.action}
                  <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
                </button>
                {results.length > 0 && <button className="wf-btn2" onClick={back}>Back</button>}
              </div>
            </div>}
        </div>
      </div>

      {}
      <div style={{
    borderTop: `1px solid ${C.border}`,
    background: C.white
  }}>
        <div style={{
    display: "flex",
    alignItems: "center",
    padding: "10px 16px",
    borderBottom: `1px solid ${C.border}`
  }}>
          <span style={{
    fontFamily: sans,
    fontSize: 12.5,
    fontWeight: 600,
    color: C.ink
  }}>Transaction event log</span>
        </div>
        <div style={{
    maxHeight: 168,
    overflowY: "auto",
    padding: "6px 0"
  }}>
          {logRows.map((r, i) => <div key={i} className={r.kind === "pending" ? "" : "wf-anim"} style={{
    display: "flex",
    alignItems: "center",
    gap: 10,
    padding: "5px 16px",
    opacity: r.kind === "pending" ? 0.5 : 1
  }}>
              <span style={{
    fontFamily: mono,
    fontSize: 11,
    color: C.sub,
    flexShrink: 0
  }}>{r.t}</span>
              <span style={{
    fontFamily: mono,
    fontSize: 10.5,
    fontWeight: 600,
    color: levelColor[r.level],
    flexShrink: 0,
    width: 58
  }}>[{r.level}]</span>
              <span style={{
    fontFamily: mono,
    fontSize: 11.5,
    color: r.kind === "err" ? C.error : C.body,
    flex: 1,
    minWidth: 0,
    whiteSpace: "nowrap",
    overflow: "hidden",
    textOverflow: "ellipsis"
  }}>
                {r.name}{r.detail ? <span style={{
    color: C.sub
  }}> · {r.detail}</span> : null}
              </span>
              <span style={{
    flexShrink: 0,
    width: 14,
    display: "inline-flex",
    justifyContent: "center"
  }}>
                {r.kind === "err" ? <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke={C.error} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18M6 6l12 12" /></svg> : r.kind === "pending" ? <span style={{
    width: 9,
    height: 9,
    borderRadius: "50%",
    border: `1.5px solid ${C.border}`
  }} /> : <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke={C.success} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>}
              </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.sub,
    lineHeight: 1.4
  }}>{f.footer}</span>
      </div>
    </div>;
};

Let users supply USDC to a third-party money market and manage the resulting protocol position from your app. Your app prepares and simulates each call; the user signs from their own wallet.

#### Demo

<DeFiDemo flow="lend" />

## Supply USDC

These examples use `viem@2.55.11`, `@morpho-org/morpho-sdk@5.4.1`, `@moonwell-fi/moonwell-sdk@0.22.0`, and `@aave-dao/aave-address-book@4.65.5`.

`clients.ts` creates pinned Base mainnet public and wallet clients from a server-side `PRIVATE_KEY`; every example imports those concrete clients and is type-checked in the [verified DeFi fixtures](https://github.com/base/docs/tree/master/examples/verified-doc-samples).

<Tabs>
  <Tab title="Morpho">
    Supply to Morpho's WETH/USDC market. Fetching by market ID avoids hardcoding its oracle, interest-rate model, and LLTV parameters.

    ```typescript supply-morpho.ts lines wrap expandable highlight={5} theme={null}
    import { publicClient, walletClient } from './clients.js';
    import { type MarketId } from '@morpho-org/blue-sdk';
    import { fetchMarketParams } from '@morpho-org/blue-sdk-viem';
    import {
      isRequirementSignature,
      morphoViemExtension,
    } from '@morpho-org/morpho-sdk';
    import { parseUnits } from 'viem';
    import { base } from 'viem/chains';

    const marketId =
      '0x8793cf302b8ffd655ab97bd1c695dbd967807e8367a65cb2f4edaf1380ba1bda' as MarketId;
    const user = walletClient.account.address;
    const client = publicClient.extend(morphoViemExtension());
    const params = await fetchMarketParams(marketId, publicClient);
    const market = client.morpho.blue(params, base.id);
    const action = market.supply({
      amount: parseUnits('1000', 6),
      userAddress: user,
      marketData: await market.getMarketData(),
    });

    const signatures = [];
    for (const requirement of await action.getRequirements()) {
      if (isRequirementSignature(requirement)) {
        signatures.push(await requirement.sign(walletClient, user));
      } else {
        const hash = await walletClient.sendTransaction(requirement);
        await publicClient.waitForTransactionReceipt({ hash });
      }
    }
    const request = action.buildTx(signatures);
    await publicClient.call({ account: user, ...request });
    const hash = await walletClient.sendTransaction(request);
    await publicClient.waitForTransactionReceipt({ hash });
    ```
  </Tab>

  <Tab title="Moonwell">
    Use the Moonwell SDK as the source of current Base deployment addresses, then call the USDC market with viem.

    ```typescript supply-moonwell.ts lines wrap expandable highlight={15,20,23,29} theme={null}
    import { publicClient, walletClient } from './clients.js';
    import { createMoonwellClient } from '@moonwell-fi/moonwell-sdk';
    import { parseAbi, parseUnits } from 'viem';

    const moonwell = createMoonwellClient({
      networks: { base: { rpcUrls: ['https://mainnet.base.org'] } },
    });
    const env = moonwell.environments.base;
    const usdc = env.tokens.USDC.address;
    const mUsdc = env.tokens.MOONWELL_USDC.address;
    const amount = parseUnits('1000', 6);

    const erc20Abi = parseAbi(['function approve(address,uint256) returns (bool)']);
    const marketAbi = parseAbi(['function mint(uint256) returns (uint256)']);
    const approval = await publicClient.simulateContract({
      account: walletClient.account,
      address: usdc, abi: erc20Abi, functionName: 'approve', args: [mUsdc, amount],
    });
    await publicClient.waitForTransactionReceipt({
      hash: await walletClient.writeContract(approval.request),
    });

    const supply = await publicClient.simulateContract({
      account: walletClient.account,
      address: mUsdc, abi: marketAbi, functionName: 'mint', args: [amount],
    });
    if (supply.result !== 0n) throw new Error(`Moonwell error code ${supply.result}`);
    await publicClient.waitForTransactionReceipt({
      hash: await walletClient.writeContract(supply.request),
    });
    ```
  </Tab>

  <Tab title="Aave">
    Resolve the Base Pool and asset addresses from Aave's official address book, then approve and supply through the Aave V3 Pool with viem.

    ```typescript supply-aave.ts lines wrap expandable highlight={12,17,20,26} theme={null}
    import { publicClient, walletClient } from './clients.js';
    import { AaveV3Base } from '@aave-dao/aave-address-book';
    import { parseAbi, parseUnits } from 'viem';

    const user = walletClient.account;
    const amount = parseUnits('1000', 6);
    const erc20Abi = parseAbi(['function approve(address,uint256) returns (bool)']);
    const poolAbi = parseAbi([
      'function supply(address,uint256,address,uint16)',
    ]);

    const approval = await publicClient.simulateContract({
      account: user, address: AaveV3Base.ASSETS.USDC.UNDERLYING,
      abi: erc20Abi, functionName: 'approve', args: [AaveV3Base.POOL, amount],
    });
    await publicClient.waitForTransactionReceipt({
      hash: await walletClient.writeContract(approval.request),
    });

    const supply = await publicClient.simulateContract({
      account: user, address: AaveV3Base.POOL, abi: poolAbi,
      functionName: 'supply',
      args: [AaveV3Base.ASSETS.USDC.UNDERLYING, amount, user.address, 0],
    });
    await publicClient.waitForTransactionReceipt({
      hash: await walletClient.writeContract(supply.request),
    });
    ```
  </Tab>
</Tabs>

<Warning>
  Supply rates are variable, withdrawals depend on market liquidity, and every integration inherits protocol, oracle, and approval risk. Display current terms and simulate the exact transaction before asking the user to sign.
</Warning>

## See also

* [Integrate borrowing](/build-on-base/integrate-defi/integrate-borrowing) · [Integrate an earn product](/build-on-base/integrate-defi/integrate-earn-product)
* [Integrate DeFi overview](/get-started/integrate-defi)
