> ## 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: Send tokens across wallets on the same blockchain

> Use the App Kit SDK to send tokens from one wallet to another on the same 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 CircleWalletsProjectSetup = ({projectName, extraPackages = ""}) => <></>;

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

<TryOnArcStudio />

This quickstart walks you through sending tokens from one wallet to another on
the same blockchain. The example in this quickstart sends USDC on Arc Testnet,
but you can use another
[supported token or blockchain](/app-kit/references/supported-blockchains).

<Tabs>
  <Tab title="Browser wallet">
    Use this flow to send USDC with a connected browser wallet. The example uses Arc
    Testnet.

    ## Prerequisites

    Before you begin, ensure that you've:

    * Installed [Node.js v22+](https://nodejs.org/).
    * Installed a browser wallet such as [MetaMask](https://metamask.io/) and added
      the
      [Arc Testnet](https://docs.arc.io/arc/references/connect-to-arc#wallet-setup)
      network.
    * Funded your wallet with testnet USDC from the
      [Circle Faucet](https://faucet.circle.com/).

    ## 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-send-browser-wallet
    cd app-kit-send-browser-wallet
    npm init -y
    npm pkg set type=module
    npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem {extraPackages}
    npm install --save-dev typescript vite
    ```

    ### 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 a browser wallet

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

    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 a Viem adapter from the selected wallet provider

    Use the discovered provider to request account access, then create the App Kit
    adapter that signs transactions in the browser:

    ```typescript TypeScript theme={null}
    import { createViemAdapterFromProvider } from "@circle-fin/adapter-viem-v2";

    async function connectBrowserWallet() {
      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,
      });

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

    <Tip>
      If multiple EVM wallets are installed, explicitly choose the wallet you want to
      use instead of relying on the first announced provider. The browser demo used to
      validate this quickstart prefers MetaMask when it is available.
    </Tip>

    ## Step 3. Send USDC

    ### 3.1. Call `kit.send()`

    This is the only App Kit-specific send call you need after the wallet is
    connected:

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

    const kit = new AppKit();

    async function sendUSDCWithBrowserWallet() {
      const { adapter, connectedAddress, walletName } =
        await connectBrowserWallet();

      const sendParams: SendParams = {
        from: { adapter, chain: "Arc_Testnet" },
        to: "RECIPIENT_ADDRESS",
        amount: "1.00",
        token: "USDC",
      };

      const estimate = await kit.estimateSend(sendParams);
      const result = await kit.send(sendParams);

      console.log(`Submitted send with ${walletName}`, {
        connectedAddress,
        estimate,
        result,
      });
      return result;
    }
    ```

    <Info>
      Using another
      [token](/app-kit/references/supported-blockchains#supported-tokens) or
      [blockchain](/app-kit/references/supported-blockchains)? Change the `token` and
      `chain` values in `kit.send()` and ensure the connected wallet holds enough
      funds to complete the transfer.
    </Info>

    ### 3.2. Verify the transaction

    After `kit.send()` resolves, inspect the returned result. Use the transaction
    explorer URL to verify the amount and recipient on the blockchain.

    The following is an example of how the result of a successful send might look in
    the browser console. The values are used in this example only and are not a real
    transaction:

    ```bash Shell theme={null}
    {
      name: "transfer",
      state: "success",
      txHash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
      explorerUrl: "https://explorer.testnet.arc.io/tx/0x1234567890abcdef...",
    }
    ```
  </Tab>

  <Tab title="Circle Wallets">
    Use this flow to send USDC with a developer-controlled wallet managed by Circle
    Wallets. The example uses Arc Testnet.

    ## Prerequisites

    Before you begin, ensure that you've:

    * Installed [Node.js v22+](https://nodejs.org/).
    * 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 a developer-controlled wallet on Arc Testnet using the Circle Console.
    * Funded your Arc Testnet wallet with testnet USDC from the
      [Circle Faucet](https://faucet.circle.com/).

    ## Step 1. Set up the project

    ### 1.1. Create the project and install dependencies

    Create a project directory, initialize a Node.js project with an ES module type
    and start script, then install runtime and dev dependencies:

    ```bash Shell theme={null}
    mkdir app-kit-send-circle-wallets
    cd app-kit-send-circle-wallets
    npm init -y
    npm pkg set type=module
    npm pkg set scripts.start="tsx --env-file=.env index.ts"
    npm install @circle-fin/app-kit @circle-fin/adapter-circle-wallets tsx {extraPackages}
    npm install --save-dev typescript @types/node
    ```

    ### 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,
    `YOUR_ENTITY_SECRET` with your entity secret. You can fetch the address from the
    [Circle Developer Console](https://developers.circle.com/w3s/circle-developer-account)
    or the
    [list wallets](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/get-wallets)
    endpoint:

    ```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. Send USDC

    ### 2.1. Create the script

    Create an `index.ts` file in the project directory and add the following code.
    This code sends 1.00 USDC from your Circle Wallets-controlled Arc Testnet wallet
    to a recipient on Arc Testnet:

    <Info>
      Using another
      [token](/app-kit/references/supported-blockchains#supported-tokens) or
      [blockchain](/app-kit/references/supported-blockchains)? Change the `token` and
      `chain` values in `kit.send()` and ensure the source wallet has enough funds to
      complete the transfer.
    </Info>

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

    const kit = new AppKit();

    const sourceWalletAddress = "YOUR_SOURCE_WALLET_ADDRESS";
    const recipientAddress = "RECIPIENT_ADDRESS";

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

    const sendParams: SendParams = {
      from: {
        adapter,
        chain: "Arc_Testnet",
        address: sourceWalletAddress,
      },
      to: recipientAddress,
      amount: "1.00",
      token: "USDC",
    };

    const estimate = await kit.estimateSend(sendParams);
    const result = await kit.send(sendParams);

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

    ### 2.2. Run the script

    Save the `index.ts` file and run the script in your terminal:

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

    ### 2.3. Verify the transaction

    After the script finishes, inspect the returned result in the terminal output.
    Use the transaction explorer URL to verify the amount and recipient on the
    blockchain.

    The following is an example of how the result of a successful send might look in
    the terminal output. The values are used in this example only and are not a real
    transaction:

    ```bash Shell theme={null}
    {
      estimate: { gas: 406817n, fee: '8138073262135265', gasPrice: 20004260545n },
      result: {
        name: 'send',
        state: 'success',
        txHash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
        explorerUrl: 'https://explorer.testnet.arc.io/tx/0x1234567890abcdef123456789...'
      }
    }
    ```
  </Tab>
</Tabs>
