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

# Sample app | Arc DeFi lend and borrow

> Collateralized lending on Arc: deposit cirBTC as collateral and borrow USDC against it using a custom lending smart contract.

export const PreviewImage = ({src, alt, portrait = false}) => <div className={`not-prose my-4 rounded-xl border border-gray-200 dark:border-white/10 overflow-hidden bg-white dark:bg-[#1F2F44] ${portrait ? "max-w-xs mx-auto" : ""}`}>
    <div className="flex items-center gap-1.5 px-3 py-2 border-b border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-white/[0.04]">
      <span className="w-2.5 h-2.5 rounded-full bg-red-400/70 dark:bg-red-400/60" />
      <span className="w-2.5 h-2.5 rounded-full bg-yellow-400/70 dark:bg-yellow-400/60" />
      <span className="w-2.5 h-2.5 rounded-full bg-green-400/70 dark:bg-green-400/60" />
    </div>
    <img src={src} alt={alt} className="block w-full h-auto" loading="lazy" />
  </div>;

export const SampleAppActions = ({back, repoUrl, arcStudioPrompt}) => {
  const prompt = arcStudioPrompt || `Clone the GitHub repo ${repoUrl} and help me run it locally, then walk me through how it works.`;
  const [copied, setCopied] = useState(false);
  const arcStudioUrl = `https://studio.arc.io/app?prompt=${encodeURIComponent(prompt)}`;
  const handleArcStudioClick = () => {
    try {
      if (typeof navigator !== "undefined" && navigator.clipboard && prompt) {
        navigator.clipboard.writeText(prompt).then(() => {
          setCopied(true);
          setTimeout(() => setCopied(false), 4000);
        }, () => {});
      }
    } catch (e) {}
  };
  return <div className="not-prose mb-6">
      <div className="flex items-center gap-3">
        {back && <a href={back} className="inline-flex items-center gap-1 text-sm text-gray-500 dark:text-[#888] hover:text-[#3E74BB] dark:hover:text-[#ACC6E9] no-underline mr-2">
            <span aria-hidden="true">←</span> Back
          </a>}
        <span className="relative inline-flex">
          <a href={arcStudioUrl} target="_blank" rel="noreferrer" onClick={handleArcStudioClick} aria-label="Try it on Arc Studio (opens in new tab)" className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-[#3E74BB] border border-[#3E74BB] text-sm font-medium text-white no-underline hover:bg-[#345f9c] hover:border-[#345f9c] transition-all">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" />
            </svg>
            Try it on Arc Studio
          </a>
          {copied && <span role="status" aria-live="polite" className="absolute left-0 top-full mt-2 w-72 text-sm text-gray-500 dark:text-[#888]">
              Opening Arc Studio — prompt copied to your clipboard in case you need to
              sign in first.
            </span>}
        </span>
        {repoUrl && <a href={repoUrl} target="_blank" rel="noreferrer" className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-white dark:bg-[#1F2F44] border border-gray-200 dark:border-white/10 text-sm font-medium text-gray-900 dark:text-white no-underline hover:border-gray-300 dark:hover:border-white/25 hover:bg-gray-50 dark:hover:bg-white/[0.06] transition-all">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
              <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
            </svg>
            Clone and edit
          </a>}
      </div>
    </div>;
};

<SampleAppActions back="/arc/references/sample-applications" repoUrl="https://github.com/circlefin/arc-defi-lend-borrow" />

Arc DeFi lend and borrow shows how to build a collateralized lending protocol on
Arc. Users deposit cirBTC (a test ERC-20 token the sample app deploys to
simulate a Bitcoin-backed asset) as collateral and borrow USDC against it. The
protocol enforces a 50% loan-to-value ratio: depositing \$100 of cirBTC lets you
borrow up to 50 USDC. The app supports both MetaMask and Circle Modular Wallets
through a unified wallet abstraction layer, following the Arc-specific USDC
patterns described in
[Stablecoin native model](/arc/concepts/stablecoin-native-model).

## Preview

<PreviewImage src="/images/sample-apps/arc-defi-lend-borrow.png" alt="Lending and borrowing dashboard showing collateral balance and available borrow amount" />

## Flow

<Steps>
  <Step title="Connect wallet">
    The user connects with MetaMask or a Circle Modular Wallet (WebAuthn
    passkey). A unified hook abstracts both wallet types for all contract
    interactions.
  </Step>

  <Step title="Mint cirBTC from the UI faucet">
    The user mints cirBTC test tokens directly from the app to use as
    collateral. USDC is used as native gas on Arc Testnet.
  </Step>

  <Step title="Approve and deposit collateral">
    The user grants an ERC-20 allowance to the `LendingBorrowing` contract, then
    deposits cirBTC. The contract locks the collateral for the duration of any
    active loan.
  </Step>

  <Step title="Borrow USDC">
    The protocol calculates the maximum amount the user can borrow at 50% of the
    deposited collateral value. The user borrows USDC up to that limit from the
    liquidity pool. Repayment equals the borrowed amount; this implementation
    does not accrue interest.
  </Step>

  <Step title="Repay loan">
    The user repays the borrowed USDC in full. Only after full repayment can
    collateral be withdrawn.
  </Step>

  <Step title="Withdraw collateral">
    With no active loan, the user withdraws their cirBTC collateral back to
    their wallet.
  </Step>
</Steps>

<Note>
  This reference implementation omits two features common in production lending
  protocols: liquidation (no mechanism removes positions with insufficient
  collateral) and interest accrual (repayment equals the borrowed amount). Add
  both before using this as a production foundation. The USDC liquidity pool
  must also be funded before users can borrow; the deployment script seeds an
  initial pool balance.
</Note>
