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

> ## Agent Instructions
> Before reading these docs, install the Circle Skill for Arc to get pre-loaded context: use-arc (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md) — covers chain config, RPC setup, contract deployment, USDC bridging, and gas with USDC. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills.
> USDC is the gas token. Arc uses USDC for gas fees, not ETH. Configure gas payment in USDC when submitting transactions.
> Read EVM differences before writing Arc code. Arc targets the Osaka EVM baseline. Most contracts deploy unchanged, but several runtime behaviors diverge from Ethereum: USDC uses 18 decimals natively (not 6), the system emitter `0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE` logs all USDC Transfer events, the mempool enforces a 20 Gwei `maxFeePerGas` floor, blocklist reverts consume gas without a receipt, and `address(0)` sends revert rather than succeed. https://docs.arc.io/arc/references/evm-differences.md is the canonical reference for all Arc-specific runtime behaviors. Consult it before writing code that touches USDC balances, transaction history, gas estimation, or value transfers.
> Sub-second finality. Transactions are final in under 1 second. No need to wait for multiple block confirmations.
> Use App Kits for multichain payment and liquidity capabilities. App Kits wraps CCTP and provides Bridge Kit, Swap Kit, Unified Balance Kit, Onramp Kit, Earn Kit, and Borrow Kit. Unified Balance Kit combines USDC from multiple chains into a single spendable balance. Earn Kit integrates earn opportunities into your app. Borrow Kit lets users borrow USDC against cirBTC collateral on Arc.
> Use Arc Foundry for contract development. Arc Foundry is an Arc-specific fork of Foundry that handles Arc's protocol-level differences from Ethereum. It provides arc-forge, arc-cast, and arc-anvil. Install it before deploying contracts: https://docs.arc.io/arc/tutorials/install-arc-foundry.md.
> Arc is available on both Testnet and Mainnet. See https://docs.arc.io/arc/references/connect-to-arc.md for RPC endpoints and https://faucet.circle.com for testnet tokens.
> Always check Contract Addresses: https://docs.arc.io/arc/references/contract-addresses.md
> Building beyond Arc? Circle offers skills for the full platform: use-usdc (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md), use-circle-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md), use-developer-controlled-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md), use-user-controlled-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md), use-modular-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md), use-gateway (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md), use-smart-contract-platform (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md). Full Circle developer docs: https://developers.circle.com/llms.txt.

# Quickstart: Deposit and spend a Unified Balance

> Deposit USDC from multiple source blockchains into a Unified Balance, then spend from the combined pool on another blockchain

export const TryOnArcStudio = () => {
  const [copied, setCopied] = useState(false);
  const [prompt, setPrompt] = useState("");
  useEffect(() => {
    const url = `https://docs.arc.io${window.location.pathname}.md`;
    setPrompt(`Read the guide at ${url}, implement it in a new project, then run it and show me how it works.`);
  }, []);
  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">
      <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>
    </div>;
};

export const BrowserWalletProjectSetup = ({projectName, extraPackages = ""}) => <></>;

<TryOnArcStudio />

Use this quickstart to deposit USDC into a Unified Balance, check the combined
balance, and spend from it on another blockchain. The examples deposit from Base
Sepolia and Solana Devnet, then spend on Arc Testnet.

Choose the wallet model that matches your application. Use a browser wallet when
the end user signs in the client, or use Circle Wallets when you manage
developer-controlled wallets through Circle.

<Tabs>
  <Tab title="Browser wallet">
    Use this flow to deposit and spend a Unified Balance with connected browser
    wallets. The examples use Base Sepolia, Solana Devnet, and Arc Testnet.

    ## Prerequisites

    Before you begin, ensure that you've:

    * Installed [Node.js v22+](https://nodejs.org/).
    * Created an EVM wallet using a wallet provider such as
      [MetaMask](https://metamask.io/) and added the
      [Base Sepolia](https://docs.base.org/docs/network-information#base-testnet-sepolia)
      and
      [Arc Testnet](https://docs.arc.io/arc/references/connect-to-arc#wallet-setup)
      networks.
    * Created a Solana wallet (for example, [Phantom](https://phantom.app/) or
      [Solflare](https://solflare.com/)) on Devnet.
    * Funded your wallets with testnet tokens:
      * Get testnet USDC from the [Circle Faucet](https://faucet.circle.com/) on
        Base Sepolia and Solana Devnet.
      * Get testnet ETH on Base Sepolia from a
        [public faucet](https://www.alchemy.com/faucets/base-sepolia) (needed for
        deposit and spend transactions on Base Sepolia).
      * Get SOL for Solana Devnet from the
        [Solana Faucet](https://faucet.solana.com/).
      * Fund the connected EVM wallet on Arc Testnet if needed (USDC on Arc can
        cover gas for the destination credit when you spend on Arc).
    * Obtained an Arc Testnet address that will receive USDC when you spend on Arc
      Testnet.

    ## Step 1. Set up the project

    ### 1.1. Create the project and install dependencies

    Create a new directory, install the App Kit packages, and add local browser demo
    tooling:

    ```bash Shell theme={null}
    mkdir app-kit-unified-balance-browser-wallet
    cd app-kit-unified-balance-browser-wallet
    npm init -y
    npm pkg set type=module
    npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem @circle-fin/adapter-solana
    npm install --save-dev typescript vite
    ```

    <Tip>
      Only need a Unified Balance and want a lighter install than the full App Kit
      SDK? Install the standalone Unified Balance Kit instead:
      `@circle-fin/unified-balance-kit`
    </Tip>

    ### 1.2. Configure TypeScript (optional)

    <Info>
      This step is optional. It helps prevent missing types in your IDE or editor.
    </Info>

    Create a `tsconfig.json` file configured for ESM and Node:

    ```bash Shell theme={null}
    cat <<'EOF' > tsconfig.json
    {
      "compilerOptions": {
        "target": "ESNext",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "strict": true,
        "types": ["node"]
      }
    }
    EOF
    ```

    ## Step 2. Connect browser wallets

    This step shows the core browser wallet integration flow: discover an
    [`EIP-6963`](https://eips.ethereum.org/EIPS/eip-6963) provider, create App Kit
    adapters from the selected providers, and pass those adapters into App Kit SDK
    methods.

    The snippets below keep wallet discovery, wallet connection, and adapter setup
    in small helper functions for readability.

    ### 2.1. Discover a browser wallet with `EIP-6963`

    <Info>
      This pattern is standards-based. The example uses MetaMask as the selected
      wallet, but the discovery flow works with any wallet that announces an
      `EIP-6963` provider.
    </Info>

    ```typescript TypeScript theme={null}
    import type { EIP1193Provider } from "viem";

    type EIP6963ProviderInfo = {
      uuid: string;
      name: string;
      icon: string;
      rdns: string;
    };

    type EIP6963ProviderDetail = {
      info: EIP6963ProviderInfo;
      provider: EIP1193Provider;
    };

    declare global {
      interface WindowEventMap {
        "eip6963:announceProvider": CustomEvent<EIP6963ProviderDetail>;
      }
    }

    async function discoverBrowserWallets(): Promise<EIP6963ProviderDetail[]> {
      const providers = new Map<string, EIP6963ProviderDetail>();

      const handleProviderAnnouncement = (
        event: WindowEventMap["eip6963:announceProvider"],
      ) => {
        providers.set(event.detail.info.uuid, event.detail);
      };

      window.addEventListener(
        "eip6963:announceProvider",
        handleProviderAnnouncement,
      );
      window.dispatchEvent(new Event("eip6963:requestProvider"));

      await new Promise((resolve) => window.setTimeout(resolve, 250));
      window.removeEventListener(
        "eip6963:announceProvider",
        handleProviderAnnouncement,
      );

      return [...providers.values()];
    }
    ```

    ### 2.2. Connect the wallet and request account access

    After you select a provider, request account access before calling an App Kit
    SDK method. This should happen in a user-triggered action such as a
    `Connect wallet` button.

    ```typescript TypeScript theme={null}
    async function connectWallet(provider: EIP1193Provider) {
      await provider.request({
        method: "eth_requestAccounts",
        params: undefined, // Required by the provider type even though this method has no params.
      });

      const accounts = (await provider.request({
        method: "eth_accounts",
        params: undefined, // Required by the provider type even though this method has no params.
      })) as string[];

      return {
        connectedAddress: accounts[0] ?? null,
      };
    }
    ```

    <Tip>
      Keep wallet connection and App Kit actions as separate user actions. This avoids
      overlapping wallet permission or chain-switch requests while a previous wallet
      prompt is still pending.
    </Tip>

    ### 2.3. Create an EVM adapter for Unified Balance

    This quickstart uses adapter-only balance checks and spend sources so the SDK
    can choose source blockchains automatically. Configure the EVM adapter with the
    EVM chains used in this flow so automatic allocation has chain context for
    balance discovery.

    ```typescript TypeScript theme={null}
    import { ArcTestnet, BaseSepolia } from "@circle-fin/app-kit/chains";
    import { createViemAdapterFromProvider } from "@circle-fin/adapter-viem-v2";

    async function connectEvmBrowserWallet() {
      const providers = await discoverBrowserWallets();
      const selectedWallet =
        providers.find(
          ({ info }) => info.rdns === "io.metamask" || info.name === "MetaMask",
        ) ?? providers[0];

      if (!selectedWallet) {
        throw new Error("No EIP-6963 browser wallet found");
      }

      const { connectedAddress } = await connectWallet(selectedWallet.provider);

      const adapter = await createViemAdapterFromProvider({
        provider: selectedWallet.provider,
        capabilities: {
          supportedChains: [BaseSepolia, ArcTestnet],
        },
      });

      return {
        adapter,
        connectedAddress,
        walletName: selectedWallet.info.name,
      };
    }
    ```

    ### 2.4. Connect the Solana wallet and create a Solana adapter

    <Info>
      This pattern assumes a Solana browser wallet that exposes `window.solana`. Keep
      wallet connection and App Kit actions as separate user actions so the wallet is
      fully connected before you call an App Kit SDK method.
    </Info>

    ```typescript TypeScript theme={null}
    import { SolanaDevnet } from "@circle-fin/app-kit/chains";
    import { createSolanaAdapterFromProvider } from "@circle-fin/adapter-solana";
    import type { CreateSolanaAdapterFromProviderParams } from "@circle-fin/adapter-solana";

    type SolanaWalletProvider = CreateSolanaAdapterFromProviderParams["provider"];

    declare global {
      interface Window {
        solana?: SolanaWalletProvider;
      }
    }

    async function connectSolanaWallet(provider: SolanaWalletProvider) {
      const connection = await provider.connect();

      return {
        connectedAddress:
          connection.publicKey?.toString() ??
          provider.publicKey?.toString() ??
          null,
      };
    }

    async function connectSolanaBrowserWallet() {
      const provider = window.solana;

      if (!provider) {
        throw new Error("No Solana browser wallet found");
      }

      const { connectedAddress } = await connectSolanaWallet(provider);

      const adapter = await createSolanaAdapterFromProvider({
        provider,
        capabilities: {
          supportedChains: [SolanaDevnet],
        },
      });

      return {
        adapter,
        connectedAddress,
      };
    }
    ```

    ## Step 3. Deposit into a Unified Balance

    In this step, you'll deposit from Base Sepolia and Solana Devnet. The EVM
    deposit uses the EVM browser wallet adapter from the previous step. The Solana
    deposit uses the Solana browser wallet adapter from the previous step.

    The examples in the remaining steps reuse the same `kit` instance and `Adapter`
    type.

    ### 3.1. Deposit from Base Sepolia

    Call `kit.unifiedBalance.deposit` with the connected EVM browser wallet adapter.
    Before the deposit, switch the browser wallet to Base Sepolia so the deposit
    authorization is signed on the source chain:

    ```typescript TypeScript theme={null}
    import { AppKit, type Adapter } from "@circle-fin/app-kit";
    import { resolveChainIdentifier } from "@circle-fin/adapter-viem-v2";

    const kit = new AppKit();

    async function depositFromBaseSepolia(evmAdapter: Adapter) {
      const chain = resolveChainIdentifier("Base_Sepolia");

      if (chain.type !== "evm") {
        throw new Error(`${chain.name} is not an EVM chain`);
      }

      await evmAdapter.ensureChain(chain);

      const result = await kit.unifiedBalance.deposit({
        from: { adapter: evmAdapter, chain: "Base_Sepolia" },
        amount: "2.00",
        token: "USDC",
      });

      console.dir(result, { depth: null });

      return result;
    }
    ```

    You'll see output like:

    ```text Shell theme={null}
    {
      amount: "2.00",
      token: "USDC",
      chain: "Base_Sepolia",
      txHash: "0x...",
      explorerUrl: "https://sepolia.basescan.org/tx/0x...",
      ...
    }
    ```

    ### 3.2. Deposit from Solana Devnet

    Call `kit.unifiedBalance.deposit` with the Solana browser wallet adapter:

    ```typescript TypeScript theme={null}
    async function depositFromSolanaDevnet(solanaAdapter: Adapter) {
      const result = await kit.unifiedBalance.deposit({
        from: { adapter: solanaAdapter, chain: "Solana_Devnet" },
        amount: "1.00",
        token: "USDC",
      });

      console.dir(result, { depth: null });

      return result;
    }
    ```

    You'll see output like:

    ```text Shell theme={null}
    {
      amount: "1.00",
      token: "USDC",
      chain: "Solana_Devnet",
      txHash: "2k41...",
      explorerUrl: "https://solscan.io/tx/2k41...?cluster=devnet",
      ...
    }
    ```

    ### 3.3. Verify the deposits

    Open the `explorerUrl` from each deposit result and confirm the onchain
    transactions on Base Sepolia and Solana Devnet. When both deposits are
    finalized, continue to the next step.

    ## Step 4. Check your Unified Balance

    In this step, you query your Unified Balance across the Base Sepolia and Solana
    Devnet depositors and print the confirmed and pending amounts.

    ### 4.1. Check balances

    Call `kit.unifiedBalance.getBalances` with the same browser wallet adapters you
    used for the deposits:

    ```typescript TypeScript theme={null}
    async function checkUnifiedBalance(
      evmAdapter: Adapter,
      solanaAdapter: Adapter,
    ) {
      const balances = await kit.unifiedBalance.getBalances({
        // Both wallets that deposited, one adapter per source.
        sources: [{ adapter: evmAdapter }, { adapter: solanaAdapter }],
        networkType: "testnet",
        includePending: true,
      });

      console.dir(balances, { depth: null });

      return balances;
    }
    ```

    You'll see output like:

    ```text Shell theme={null}
    {
      token: "USDC",
      totalConfirmedBalance: "3.00",
      totalPendingBalance: "0.00",
      breakdown: [
        {
          depositor: "0x...",
          totalConfirmed: "2.00",
          totalPending: "0.00",
          breakdown: [{ chain: "Base_Sepolia", confirmedBalance: "2.00", ... }]
        },
        {
          depositor: "...",
          totalConfirmed: "1.00",
          totalPending: "0.00",
          breakdown: [{ chain: "Solana_Devnet", confirmedBalance: "1.00", ... }]
        }
      ]
    }
    ```

    After a deposit, funds can appear in `totalPendingBalance` before they are
    reflected in `totalConfirmedBalance`. Wait until the confirmed balance is
    sufficient before you spend.

    ## Step 5. Spend from the combined balance

    In this step, you spend USDC on Arc Testnet from your Unified Balance.

    ### 5.1. Spend on Arc Testnet

    Collect the recipient address from your app UI, then pass it with the connected
    wallet adapters into the spend function. This code spends 2.50 USDC on Arc
    Testnet for the recipient.
    [The App Kit SDK chooses](/app-kit/tutorials/unified-balance/select-source-blockchains)
    how much USDC to use from each blockchain.

    ```typescript TypeScript theme={null}
    async function spendFromUnifiedBalance(
      evmAdapter: Adapter,
      solanaAdapter: Adapter,
      recipientAddress: string,
    ) {
      console.log(`Spending 2.50 USDC on Arc_Testnet for ${recipientAddress}...`);

      const result = await kit.unifiedBalance.spend({
        amount: "2.50",
        token: "USDC",
        from: [{ adapter: evmAdapter }, { adapter: solanaAdapter }],
        to: {
          adapter: evmAdapter,
          chain: "Arc_Testnet",
          recipientAddress,
        },
      });

      console.dir(result, { depth: null });

      return result;
    }
    ```

    <Tip>
      You can customize your Unified Balance to
      [use fast deposits](/app-kit/tutorials/unified-balance/use-fast-deposits),
      [collect a custom fee](/app-kit/tutorials/unified-balance/collect-custom-spend-fees)
      from end users,
      [estimate fees](/app-kit/tutorials/unified-balance/estimate-spend-fees) before
      spending,
      [select source blockchains and allocations](/app-kit/tutorials/unified-balance/select-source-blockchains)
      to fund a balance, or use the
      [Forwarding Service](/app-kit/tutorials/unified-balance/use-forwarding-service).
      For normal movement out of a Unified Balance, use `spend`. Use
      [`removeFund`](/app-kit/tutorials/unified-balance/remove-funds-trustlessly) only
      as a trustless recovery path when the normal spend flow is unavailable; the
      process requires a seven-day delay before you can withdraw.
    </Tip>

    When the spend completes, you should see output similar to:

    ```bash Shell theme={null}
    Spending 2.50 USDC on Arc_Testnet for 0x...

    { recipientAddress: "0x...", destinationChain: "Arc Testnet", txHash: "0x...", ... }
    ```

    ### 5.2. Verify the spend

    Use the `explorerUrl` from the spend result to confirm that USDC arrived at the
    recipient address on Arc Testnet. The received amount can be less than the
    requested spend after fees. For more on fees, see
    [How Unified Balance fees work](/app-kit/concepts/unified-balance-fees).
  </Tab>

  <Tab title="Circle Wallets">
    Use this flow to deposit and spend a Unified Balance with developer-controlled
    wallets managed by Circle Wallets. The examples use Base Sepolia, Solana Devnet,
    and Arc Testnet.

    ## Prerequisites

    Before you begin, ensure that you've:

    * Installed [Node.js v22+](https://nodejs.org/).
    * Set up Circle Wallets:
      * Obtained a
        [API Key](https://developers.circle.com/api-reference/keys#creating-an-api-key-for-developer-services)
        and
        [entity secret](https://developers.circle.com/wallets/dev-controlled/register-entity-secret)
        from the
        [Circle Console](https://developers.circle.com/w3s/circle-developer-account).
      * Created developer-controlled wallets on Base Sepolia, Solana Devnet, and Arc
        Testnet.
    * Funded the wallets:
      * Base Sepolia: testnet USDC from the
        [Circle Faucet](https://faucet.circle.com/) and testnet ETH from a
        [public faucet](https://www.alchemy.com/faucets/base-sepolia).
      * Solana Devnet: testnet USDC from the
        [Circle Faucet](https://faucet.circle.com/) and SOL from the
        [Solana Faucet](https://faucet.solana.com/).
      * Arc Testnet: fund the destination wallet if needed. USDC on Arc can cover
        gas for the destination credit when you spend on Arc.

    ## Step 1. Set up the project

    ### 1.1. Create the project and install dependencies

    Create a new directory and install the App Kit SDK with the Circle Wallets
    adapter and supporting tools:

    ```bash Shell theme={null}
    # Set up your directory and initialize a Node.js project
    mkdir app-kit-unified-balance-circle-wallets
    cd app-kit-unified-balance-circle-wallets
    npm init -y
    npm pkg set type=module

    # Set up run scripts
    npm pkg set scripts.deposit:base="tsx --env-file=.env deposit-base.ts"
    npm pkg set scripts.deposit:solana="tsx --env-file=.env deposit-solana.ts"
    npm pkg set scripts.balance="tsx --env-file=.env check-balance.ts"
    npm pkg set scripts.spend="tsx --env-file=.env spend.ts"

    # Install runtime dependencies
    npm install @circle-fin/app-kit @circle-fin/adapter-circle-wallets tsx

    # Install dev dependencies
    npm install --save-dev typescript @types/node
    ```

    <Tip>
      Only need a Unified Balance and want a lighter install than the full App Kit
      SDK? Install the standalone Unified Balance Kit instead:
      `@circle-fin/unified-balance-kit`
    </Tip>

    ### 1.2. Configure TypeScript (optional)

    <Info>
      This step is optional. It helps prevent missing types in your IDE or editor.
    </Info>

    Create a `tsconfig.json` file configured for ESM and Node:

    ```bash Shell theme={null}
    cat <<'EOF' > tsconfig.json
    {
      "compilerOptions": {
        "target": "ESNext",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "strict": true,
        "types": ["node"]
      }
    }
    EOF
    ```

    ### 1.3. Set environment variables

    Create an `.env` file in the project directory:

    ```bash Shell theme={null}
    touch .env
    ```

    Add your credentials. Replace `YOUR_API_KEY` with your Circle Developer API key
    and `YOUR_ENTITY_SECRET` with your entity secret:

    ```text .env theme={null}
    CIRCLE_API_KEY=YOUR_API_KEY
    CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET
    ```

    <Tip>
      Edit `.env` files in your IDE or editor so credentials are not leaked to your
      shell history.
    </Tip>

    ## Step 2. Deposit into a Unified Balance

    Circle Wallets uses developer-controlled addresses, so each operation includes
    the wallet address explicitly.

    <Info>
      The API key, entity secret, and deposit wallet addresses must belong to the same
      Circle Developer entity. Otherwise, Circle Wallets may fail to find the wallet
      and return error `156001` during signing.
    </Info>

    ### 2.1. Deposit from Base Sepolia

    Create a `deposit-base.ts` file. This script deposits 2.00 USDC from your Base
    Sepolia Circle Wallets-controlled wallet into your Unified Balance.

    ```typescript TypeScript theme={null}
    import { AppKit } from "@circle-fin/app-kit";
    import { createCircleWalletsAdapter } from "@circle-fin/adapter-circle-wallets";

    const kit = new AppKit();

    kit.on("*", (payload) => {
      console.log("Event received:", payload);
    });

    const adapter = createCircleWalletsAdapter({
      apiKey: process.env.CIRCLE_API_KEY!,
      entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
    });

    const baseWalletAddress = "YOUR_BASE_SEPOLIA_WALLET_ADDRESS";

    const result = await kit.unifiedBalance.deposit({
      from: {
        adapter,
        chain: "Base_Sepolia",
        address: baseWalletAddress,
      },
      amount: "2.00",
      token: "USDC",
    });

    console.dir(result, { depth: null, colors: true });
    ```

    Run the script:

    ```bash Shell theme={null}
    npm run deposit:base
    ```

    ### 2.2. Deposit from Solana Devnet

    Create a `deposit-solana.ts` file. This script deposits 1.00 USDC from your
    Solana Devnet Circle Wallets-controlled wallet into your Unified Balance.

    ```typescript TypeScript theme={null}
    import { AppKit } from "@circle-fin/app-kit";
    import { createCircleWalletsAdapter } from "@circle-fin/adapter-circle-wallets";

    const kit = new AppKit();

    kit.on("*", (payload) => {
      console.log("Event received:", payload);
    });

    const adapter = createCircleWalletsAdapter({
      apiKey: process.env.CIRCLE_API_KEY!,
      entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
    });

    const solanaWalletAddress = "YOUR_SOLANA_DEVNET_WALLET_ADDRESS";

    const result = await kit.unifiedBalance.deposit({
      from: {
        adapter,
        chain: "Solana_Devnet",
        address: solanaWalletAddress,
      },
      amount: "1.00",
      token: "USDC",
    });

    console.dir(result, { depth: null, colors: true });
    ```

    Run the script:

    ```bash Shell theme={null}
    npm run deposit:solana
    ```

    ### 2.3. Verify the deposits

    Open the `explorerUrl` from each deposit result and confirm the onchain
    transactions on Base Sepolia and Solana Devnet. When both deposits are
    finalized, continue to the next step.

    <Tip>
      You can customize your Unified Balance to
      [use fast deposits](/app-kit/tutorials/unified-balance/use-fast-deposits),
      [collect a custom fee](/app-kit/tutorials/unified-balance/collect-custom-spend-fees)
      from end users,
      [estimate fees](/app-kit/tutorials/unified-balance/estimate-spend-fees) before
      spending,
      [select source blockchains and allocations](/app-kit/tutorials/unified-balance/select-source-blockchains)
      to fund a balance, or use the
      [Forwarding Service](/app-kit/tutorials/unified-balance/use-forwarding-service).
      For normal movement out of a Unified Balance, use `spend`. Use
      [`removeFund`](/app-kit/tutorials/unified-balance/remove-funds-trustlessly) only
      as a trustless recovery path when the normal spend flow is unavailable; the
      process requires a seven-day delay before you can withdraw.
    </Tip>

    ## Step 3. Check your Unified Balance

    After both deposits are finalized, create a `check-balance.ts` file. This script
    queries the confirmed and pending Unified Balance for the Base Sepolia and
    Solana Devnet source accounts.

    ```typescript TypeScript theme={null}
    import { AppKit } from "@circle-fin/app-kit";
    import { createCircleWalletsAdapter } from "@circle-fin/adapter-circle-wallets";

    const kit = new AppKit();

    const adapter = createCircleWalletsAdapter({
      apiKey: process.env.CIRCLE_API_KEY!,
      entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
    });

    const baseWalletAddress = "YOUR_BASE_SEPOLIA_WALLET_ADDRESS";
    const solanaWalletAddress = "YOUR_SOLANA_DEVNET_WALLET_ADDRESS";

    const balances = await kit.unifiedBalance.getBalances({
      sources: [
        {
          adapter,
          address: baseWalletAddress,
          chains: ["Base_Sepolia"],
        },
        {
          adapter,
          address: solanaWalletAddress,
          chains: ["Solana_Devnet"],
        },
      ],
      networkType: "testnet",
      includePending: true,
    });

    console.dir(balances, { depth: null, colors: true });
    ```

    Run the script:

    ```bash Shell theme={null}
    npm run balance
    ```

    Wait until `totalConfirmedBalance` is high enough for the spend you plan to
    make.

    ## Step 4. Spend from the Unified Balance

    Create a `spend.ts` file. This script spends 2.50 USDC on Arc Testnet. The
    `from` sources do not include `allocations`, so the SDK chooses source
    blockchains automatically from the available confirmed balances. Each `from`
    entry needs its own adapter instance.

    ```typescript TypeScript theme={null}
    import { AppKit } from "@circle-fin/app-kit";
    import { createCircleWalletsAdapter } from "@circle-fin/adapter-circle-wallets";

    const kit = new AppKit();

    kit.on("*", (payload) => {
      console.log("Event received:", payload);
    });

    const evmAdapter = createCircleWalletsAdapter({
      apiKey: process.env.CIRCLE_API_KEY!,
      entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
    });

    const solanaAdapter = createCircleWalletsAdapter({
      apiKey: process.env.CIRCLE_API_KEY!,
      entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
    });

    const baseWalletAddress = "YOUR_BASE_SEPOLIA_WALLET_ADDRESS";
    const solanaWalletAddress = "YOUR_SOLANA_DEVNET_WALLET_ADDRESS";
    const arcWalletAddress = "YOUR_ARC_TESTNET_WALLET_ADDRESS";

    const result = await kit.unifiedBalance.spend({
      amount: "2.50",
      token: "USDC",
      from: [
        {
          adapter: evmAdapter,
          address: baseWalletAddress,
          sourceAccount: baseWalletAddress,
        },
        {
          adapter: solanaAdapter,
          address: solanaWalletAddress,
          sourceAccount: solanaWalletAddress,
        },
      ],
      to: {
        adapter: evmAdapter,
        chain: "Arc_Testnet",
        address: arcWalletAddress,
        recipientAddress: arcWalletAddress,
      },
    });

    console.dir(result, { depth: null, colors: true });
    ```

    Run the script:

    ```bash Shell theme={null}
    npm run spend
    ```

    ### 4.1. Verify the spend

    Use the `explorerUrl` from the spend result to confirm that USDC arrived at the
    recipient address on Arc Testnet. The spend result includes the allocations
    selected by the SDK, the destination recipient, and the Arc Testnet mint
    transaction hash.
  </Tab>
</Tabs>
