# Table of Contents - [App Kit: Send - Arc Docs](#app-kit-send-arc-docs) - [Welcome to Arc docs - Arc Docs](#welcome-to-arc-docs-arc-docs) - [App Kit: Swap - Arc Docs](#app-kit-swap-arc-docs) - [How swap fees work - Arc Docs](#how-swap-fees-work-arc-docs) - [Arc MCP server - Arc Docs](#arc-mcp-server-arc-docs) - [App Kit supported blockchains and tokens - Arc Docs](#app-kit-supported-blockchains-and-tokens-arc-docs) - [Install App Kit - Arc Docs](#install-app-kit-arc-docs) - [How bridge fees work - Arc Docs](#how-bridge-fees-work-arc-docs) - [App Kit: Bridge - Arc Docs](#app-kit-bridge-arc-docs) - [Consensus layer - Arc Docs](#consensus-layer-arc-docs) - [How to: Configure transfer speed and maximum cost - Arc Docs](#how-to-configure-transfer-speed-and-maximum-cost-arc-docs) - [How to: Collect custom swap fees - Arc Docs](#how-to-collect-custom-swap-fees-arc-docs) - [Arc Network - Arc Docs](#arc-network-arc-docs) - [How-to: Estimate swap rate - Arc Docs](#how-to-estimate-swap-rate-arc-docs) - [How to: Use the CCTP forwarding service - Arc Docs](#how-to-use-the-cctp-forwarding-service-arc-docs) - [How to: Estimate costs before bridging - Arc Docs](#how-to-estimate-costs-before-bridging-arc-docs) - [How to: Specify a recipient address - Arc Docs](#how-to-specify-a-recipient-address-arc-docs) - [Quickstart: Send tokens across wallets on the same blockchain - Arc Docs](#quickstart-send-tokens-across-wallets-on-the-same-blockchain-arc-docs) - [How to: Collect custom bridge fees - Arc Docs](#how-to-collect-custom-bridge-fees-arc-docs) - [App Kit - Arc Docs](#app-kit-arc-docs) - [Quickstart: Swap tokens on a blockchain - Arc Docs](#quickstart-swap-tokens-on-a-blockchain-arc-docs) - [Quickstart: Bridge between Solana and EVM - Arc Docs](#quickstart-bridge-between-solana-and-evm-arc-docs) - [Quickstart: Bridge between EVM chains - Arc Docs](#quickstart-bridge-between-evm-chains-arc-docs) - [Error recovery and troubleshooting for bridges - Arc Docs](#error-recovery-and-troubleshooting-for-bridges-arc-docs) - [Quickstart: Bridge with Circle Wallets - Arc Docs](#quickstart-bridge-with-circle-wallets-arc-docs) - [Quickstart: Swap tokens across chains - Arc Docs](#quickstart-swap-tokens-across-chains-arc-docs) - [Adapter setups - Arc Docs](#adapter-setups-arc-docs) - [How-to: Set slippage tolerance or stop limit on swaps - Arc Docs](#how-to-set-slippage-tolerance-or-stop-limit-on-swaps-arc-docs) - [App Kit SDK reference - Arc Docs](#app-kit-sdk-reference-arc-docs) - [Deterministic finality and settlement - Arc Docs](#deterministic-finality-and-settlement-arc-docs) - [Execution layer - Arc Docs](#execution-layer-arc-docs) - [Unknown](#unknown) - [Opt-in privacy - Arc Docs](#opt-in-privacy-arc-docs) - [Fees - Arc Docs](#fees-arc-docs) - [Post-quantum security - Arc Docs](#post-quantum-security-arc-docs) - [Running a node - Arc Docs](#running-a-node-arc-docs) - [Architecture - Arc Docs](#architecture-arc-docs) - [Contract addresses - Arc Docs](#contract-addresses-arc-docs) - [Connect to Arc - Arc Docs](#connect-to-arc-arc-docs) - [EVM compatibility - Arc Docs](#evm-compatibility-arc-docs) - [Gas and fees - Arc Docs](#gas-and-fees-arc-docs) - [Node requirements - Arc Docs](#node-requirements-arc-docs) - [Unknown](#unknown) - [Sample apps - Arc Docs](#sample-apps-arc-docs) - [Compliance - Arc Docs](#compliance-arc-docs) - [Data indexers - Arc Docs](#data-indexers-arc-docs) - [Account abstraction - Arc Docs](#account-abstraction-arc-docs) - [Deploying a node as a service - Arc Docs](#deploying-a-node-as-a-service-arc-docs) - [Integrate with Arc - Arc Docs](#integrate-with-arc-arc-docs) - [Node providers - Arc Docs](#node-providers-arc-docs) - [Monitoring a node - Arc Docs](#monitoring-a-node-arc-docs) - [Run an Arc node - Arc Docs](#run-an-arc-node-arc-docs) - [Deploy on Arc - Arc Docs](#deploy-on-arc-arc-docs) - [Connect to Arc - Arc Docs](#connect-to-arc-arc-docs) - [Build on Arc - Arc Docs](#build-on-arc-arc-docs) - [Deploy on Arc - Arc Docs](#deploy-on-arc-arc-docs) - [Terms of Service - Arc Docs](#terms-of-service-arc-docs) - [Bridge USDC to Arc - Arc Docs](#bridge-usdc-to-arc-arc-docs) - [Monitor contract events - Arc Docs](#monitor-contract-events-arc-docs) - [Transfer USDC or EURC - Arc Docs](#transfer-usdc-or-eurc-arc-docs) - [Interact with contracts - Arc Docs](#interact-with-contracts-arc-docs) - [Access USDC crosschain - Arc Docs](#access-usdc-crosschain-arc-docs) - [Deploy contracts - Arc Docs](#deploy-contracts-arc-docs) - [Create your first ERC-8183 job - Arc Docs](#create-your-first-erc-8183-job-arc-docs) - [Register your first AI agent - Arc Docs](#register-your-first-ai-agent-arc-docs) --- # App Kit: Send - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/send#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Send App Kit: Send [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Quick look](https://docs.arc.network/app-kit/send#quick-look) * [Installation](https://docs.arc.network/app-kit/send#installation) [App Kit](https://docs.arc.network/app-kit) includes the Send capability that lets you send tokens from one wallet to another on the same blockchain. You can use an available [token alias](https://docs.arc.network/app-kit/references/supported-blockchains#token-aliases) or the token’s contract address. [​](https://docs.arc.network/app-kit/send#quick-look) Quick look ------------------------------------------------------------------- This example sends USDC from one wallet to another in a single method call: TypeScript // Send 1.00 USDC to a wallet on Arc Testnet const result = await kit.send({ from: { adapter, chain: "Arc_Testnet" }, to: "RECIPIENT_ADDRESS", amount: "1.00", token: "USDC", }); [​](https://docs.arc.network/app-kit/send#installation) Installation ----------------------------------------------------------------------- [Install App Kit](https://docs.arc.network/app-kit/tutorials/installation) to start [sending tokens](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain) on the same blockchain. Was this page helpful? YesNo [Adapter setups](https://docs.arc.network/app-kit/tutorials/adapter-setups) [Send tokens across wallets](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Welcome to Arc docs - Arc Docs [Skip to main content](https://docs.arc.network/#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Welcome to Arc docs [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) Arc developer documentation =========================== Everything you need to build onchain finance with stablecoins: start fast, scale reliably. Use cases --------- Agentic economy --------------- Enable autonomous AI agents to coordinate, contract, and settle value in real time. Peer-to-peer payments --------------------- Launch instant, low-cost, peer-to-peer payments with stablecoin-native transfers and deterministic settlement. Stablecoin FX ------------- Build real-time, onchain stablecoin FX products with transparent pricing, instant settlement, and predictable fees. Workflows --------- Learn [Key features](https://docs.arc.network/arc-chain) [Architecture](https://docs.arc.network/arc/concepts/system-overview) [Gas and fees](https://docs.arc.network/arc/references/gas-and-fees) Build [Kits](https://docs.arc.network/app-kit) [Quickstarts](https://docs.arc.network/arc/tutorials/deploy-contracts) [Sample apps](https://docs.arc.network/arc/references/sample-applications) Integrate [Connect to Arc](https://docs.arc.network/arc/references/connect-to-arc) [Contract addresses](https://docs.arc.network/arc/references/contract-addresses) [EVM compatibility](https://docs.arc.network/arc/references/evm-compatibility) Common tasks ------------ Core [Connect to RPC](https://docs.arc.network/arc/references/connect-to-arc) [Deploy a contract](https://docs.arc.network/arc/tutorials/deploy-contracts) [Read events/logs](https://docs.arc.network/arc/tutorials/monitor-contract-events) Operate [Estimate fees](https://docs.arc.network/arc/references/gas-and-fees) [Send stablecoins](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc) Move Crosschain [Bridge in/out](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc) [Supported networks](https://docs.arc.network/app-kit/references/supported-blockchains) [Crosschain troubleshooting](https://docs.arc.network/app-kit/references/bridge-error-recovery) Build with AI ------------- [Arc MCP ServerSetup guide](https://docs.arc.network/ai/mcp) [LLMs.txtAgent context](https://docs.arc.network/llms.txt) What’s new ---------- Mar 10ReleaseApp Kit is now available ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # App Kit: Swap - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/swap#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Swap App Kit: Swap [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Quick look](https://docs.arc.network/app-kit/swap#quick-look) * [Installation](https://docs.arc.network/app-kit/swap#installation) [App Kit](https://docs.arc.network/app-kit) includes the Swap capability that lets you swap two tokens on the same blockchain in a few lines of code. If you only need to swap and don’t want the full App Kit, you can [install](https://docs.arc.network/app-kit/swap#installation) the Swap package on its own. You need a (free) kit key from [Circle Console](https://console.circle.com/) to use Swap. Among testnets, only Arc Testnet supports Swap (USDC and EURC only). Use mainnet for Swap on any other blockchains. [​](https://docs.arc.network/app-kit/swap#quick-look) Quick look ------------------------------------------------------------------- This example swaps USDC for EURC in a single method call: TypeScript // Swap 1.00 USDC for EURC on Arc Testnet const result = await kit.swap({ from: { adapter: viemAdapter, chain: "Arc_Testnet" }, tokenIn: "USDC", tokenOut: "EURC", amountIn: "1.00", config: { kitKey: process.env.KIT_KEY as string, // Your kit key from the Circle Console }, }); [​](https://docs.arc.network/app-kit/swap#installation) Installation ----------------------------------------------------------------------- App Kit comes with the Swap capability installed by default. If you’ve already [installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) , you can skip this section. If you only need to swap and don’t want the full App Kit, you can install just the Swap package. Install the Swap package and the adapter that matches your environment: * Viem * Ethers * Solana * Circle Wallets npm yarn npm install @circle-fin/swap-kit @circle-fin/adapter-viem-v2 viem npm yarn npm install @circle-fin/swap-kit @circle-fin/adapter-ethers-v6 ethers npm yarn npm install @circle-fin/swap-kit @circle-fin/adapter-solana-kit solana npm yarn npm install @circle-fin/swap-kit @circle-fin/adapter-circle-wallets Was this page helpful? YesNo [Error recovery](https://docs.arc.network/app-kit/references/bridge-error-recovery) [Swap tokens on a chain](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How swap fees work - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/concepts/swap-fees#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Swap How swap fees work [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Fees breakdown](https://docs.arc.network/app-kit/concepts/swap-fees#fees-breakdown) * [Funds flow](https://docs.arc.network/app-kit/concepts/swap-fees#funds-flow) * [Best practices for custom fees](https://docs.arc.network/app-kit/concepts/swap-fees#best-practices-for-custom-fees) This guide explains which fees apply when performing a swap, how funds move through a swap transaction, and best practices for [implementing custom swap fees](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee) . [​](https://docs.arc.network/app-kit/concepts/swap-fees#fees-breakdown) Fees breakdown ----------------------------------------------------------------------------------------- Every swap can incur the following fees: * **Your custom fee**: The extra amount you charge on top of the swap transaction. Arc keeps 10% of this amount. The remaining 90% goes to the fee recipient you configure on the source blockchain. * **Provider fee**: A fee charged by the underlying swap service provider for executing the swap. This fee is **2 basis points** (0.02%) of the swap amount. The total amount your end user pays for a swap includes the swap amount plus all fees above. [​](https://docs.arc.network/app-kit/concepts/swap-fees#funds-flow) Funds flow --------------------------------------------------------------------------------- The following example shows what happens when a user initiates a swap with a **1% custom fee** (1,000 USDC to USDT): 1. The user initiates a swap for 1,000 USDC to USDT. 2. Your custom fee of 10 USDC (1%) is configured. 3. The source wallet signs a transaction for **1,000 USDC**. 4. The **10 USDC custom fee is collected and split**: * Arc receives **1 USDC** (10% of the custom fee). * Your configured fee recipient receives **9 USDC** (90% of the custom fee). 5. The **swap service provider charges a 2 bps provider fee** (0.02%) of the remaining amount. For 990 USDC, this is **0.198 USDC**. 6. The swap executes with a remaining input amount of 989.802 USDC and the user receives the net output amount in USDT. This flow is illustrated in the following diagram: [​](https://docs.arc.network/app-kit/concepts/swap-fees#best-practices-for-custom-fees) Best practices for custom fees ------------------------------------------------------------------------------------------------------------------------- Follow these best practices when implementing custom fees for swaps: * Use a fee recipient address in the same network context where the swap originates. * Return fee amounts in human-readable decimal format (for example, `0.20` instead of `200000` for 0.20 USDC). App Kit handles base-unit conversion internally. Was this page helpful? YesNo [Set slippage tolerance or stop limit](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit) [Swap tokens across chains](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Arc MCP server - Arc Docs [Skip to main content](https://docs.arc.network/ai/mcp#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Build with AI Arc MCP server [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Claude Code](https://docs.arc.network/ai/mcp#claude-code) * [Claude Desktop](https://docs.arc.network/ai/mcp#claude-desktop) * [Cursor](https://docs.arc.network/ai/mcp#cursor) * [VS Code (Copilot)](https://docs.arc.network/ai/mcp#vs-code-copilot) * [Windsurf](https://docs.arc.network/ai/mcp#windsurf) * [Other MCP clients](https://docs.arc.network/ai/mcp#other-mcp-clients) * [Verify the connection](https://docs.arc.network/ai/mcp#verify-the-connection) The Arc Model Context Protocol (MCP) server gives AI tools direct access to Arc documentation so they can search for relevant content and retrieve full pages during conversations. It is hosted at `https://docs.arc.network/mcp` and requires no authentication. The server exposes two tools: * **Search** — finds relevant documentation snippets based on a query. * **Get page** — retrieves the full content of a specific documentation page. For a machine-readable index of all documentation pages, see the [`llms.txt` file](https://docs.arc.network/llms.txt) . [​](https://docs.arc.network/ai/mcp#claude-code) Claude Code --------------------------------------------------------------- Run the following command to add the Arc MCP server: claude mcp add --transport http arc-docs https://docs.arc.network/mcp Claude Code automatically discovers the server’s tools on the next conversation. [​](https://docs.arc.network/ai/mcp#claude-desktop) Claude Desktop --------------------------------------------------------------------- 1. Open **Settings** and navigate to **Connectors**. 2. Select **Add custom connector**. 3. Enter `Arc Docs` as the name and `https://docs.arc.network/mcp` as the URL. 4. During a chat, use the attachments button to select the Arc Docs connector. [​](https://docs.arc.network/ai/mcp#cursor) Cursor ----------------------------------------------------- Add the following to your `mcp.json` file (accessible via **Cursor Settings > MCP**): { "mcpServers": { "arc-docs": { "url": "https://docs.arc.network/mcp" } } } [​](https://docs.arc.network/ai/mcp#vs-code-copilot) VS Code (Copilot) ------------------------------------------------------------------------- Create or update `.vscode/mcp.json` in your project root: { "servers": { "arc-docs": { "type": "http", "url": "https://docs.arc.network/mcp" } } } [​](https://docs.arc.network/ai/mcp#windsurf) Windsurf --------------------------------------------------------- Add the following to your Windsurf MCP configuration: { "mcpServers": { "arc-docs": { "serverUrl": "https://docs.arc.network/mcp" } } } [​](https://docs.arc.network/ai/mcp#other-mcp-clients) Other MCP clients --------------------------------------------------------------------------- Any MCP-compatible client can connect using the HTTP transport at `https://docs.arc.network/mcp`. Most clients require only the server URL and transport type (`http`). Refer to your client’s documentation for the exact configuration format. [​](https://docs.arc.network/ai/mcp#verify-the-connection) Verify the connection ----------------------------------------------------------------------------------- After adding the server, confirm the connection by asking your AI tool a question about Arc, such as “What smart contract standards does Arc support?” The tool should return content sourced from Arc documentation. If it does not: * **Check the URL** — confirm it is exactly `https://docs.arc.network/mcp` with no trailing path. * **Check network access** — the server must be reachable over HTTPS from your machine. * **Restart the client** — some tools only detect new MCP servers after a restart or new session. Was this page helpful? YesNo [Deploy on Arc](https://docs.arc.network/arc/tutorials/deploy-on-arc) [llms.txt](https://docs.arc.network/ai/llms) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # App Kit supported blockchains and tokens - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/references/supported-blockchains#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Get started App Kit supported blockchains and tokens [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Supported blockchains](https://docs.arc.network/app-kit/references/supported-blockchains#supported-blockchains) * [Supported tokens](https://docs.arc.network/app-kit/references/supported-blockchains#supported-tokens) * [Token aliases](https://docs.arc.network/app-kit/references/supported-blockchains#token-aliases) [​](https://docs.arc.network/app-kit/references/supported-blockchains#supported-blockchains) Supported blockchains --------------------------------------------------------------------------------------------------------------------- Pick a tab to check blockchain support for each of App Kit’s capabilities or adapters. * Capabilities * Adapters The following tables list blockchains that App Kit supports for each capability, split by mainnet and testnet. ### [​](https://docs.arc.network/app-kit/references/supported-blockchains#mainnet) Mainnet | Blockchain | Send | Bridge | Swap | | --- | --- | --- | --- | | Arbitrum | ✅ | ✅ | ✅ | | Avalanche | ✅ | ✅ | ✅ | | Base | ✅ | ✅ | ✅ | | Codex | ✅ | ✅ | ❌ | | EDGE | ✅ | ✅ | ❌ | | Ethereum | ✅ | ✅ | ✅ | | HyperEVM | ✅ | ✅ | ✅ | | Ink | ✅ | ✅ | ✅ | | Linea | ✅ | ✅ | ✅ | | Monad | ✅ | ✅ | ✅ | | Morph | ✅ | ✅ | ❌ | | OP Mainnet | ✅ | ✅ | ✅ | | Plume | ✅ | ✅ | ✅ | | Polygon PoS | ✅ | ✅ | ✅ | | Sei | ✅ | ✅ | ✅ | | Solana | ✅ | ✅ | ✅ | | Sonic | ✅ | ✅ | ✅ | | Unichain | ✅ | ✅ | ✅ | | World Chain | ✅ | ✅ | ✅ | | XDC | ✅ | ✅ | ✅ | ### [​](https://docs.arc.network/app-kit/references/supported-blockchains#testnet) Testnet Among testnets, only Arc Testnet supports Swap (USDC and EURC only). Use mainnet for Swap on any other blockchains. | Blockchain | Send | Bridge | Swap | | --- | --- | --- | --- | | Arbitrum Sepolia | ✅ | ✅ | ❌ | | Arc Testnet | ✅ | ✅ | ✅ | | Avalanche Fuji | ✅ | ✅ | ❌ | | Base Sepolia | ✅ | ✅ | ❌ | | Codex Testnet | ✅ | ✅ | ❌ | | EDGE Testnet | ✅ | ✅ | ❌ | | Ethereum Sepolia | ✅ | ✅ | ❌ | | HyperEVM Testnet | ✅ | ✅ | ❌ | | Ink Testnet | ✅ | ✅ | ❌ | | Linea Sepolia | ✅ | ✅ | ❌ | | Monad Testnet | ✅ | ✅ | ❌ | | Morph Testnet | ✅ | ✅ | ❌ | | OP Sepolia | ✅ | ✅ | ❌ | | Plume Testnet | ✅ | ✅ | ❌ | | Polygon PoS Amoy | ✅ | ✅ | ❌ | | Sei Testnet | ✅ | ✅ | ❌ | | Solana Devnet | ✅ | ✅ | ❌ | | Sonic Testnet | ✅ | ✅ | ❌ | | Unichain Sepolia | ✅ | ✅ | ❌ | | World Chain Sepolia | ✅ | ✅ | ❌ | | XDC Apothem | ✅ | ✅ | ❌ | The following tables list blockchains that App Kit supports for chain adapters (Viem, Ethers, Solana) and the Circle Wallets adapter, split by mainnet and testnet. ### [​](https://docs.arc.network/app-kit/references/supported-blockchains#mainnet-2) Mainnet | Blockchain | Chain adapters | Circle Wallets adapter | | --- | --- | --- | | Arbitrum | ✅ | ✅ | | Avalanche | ✅ | ✅ | | Base | ✅ | ✅ | | Codex | ✅ | ❌ | | EDGE | ✅ | ❌ | | Ethereum | ✅ | ✅ | | HyperEVM | ✅ | ❌ | | Ink | ✅ | ❌ | | Linea | ✅ | ❌ | | Monad | ✅ | ❌ | | Morph | ✅ | ❌ | | OP Mainnet | ✅ | ✅ | | Plume | ✅ | ❌ | | Polygon PoS | ✅ | ✅ | | Sei | ✅ | ❌ | | Solana | ✅ | ✅ | | Sonic | ✅ | ❌ | | Unichain | ✅ | ✅ | | World Chain | ✅ | ❌ | | XDC | ✅ | ❌ | ### [​](https://docs.arc.network/app-kit/references/supported-blockchains#testnet-2) Testnet | Blockchain | Chain adapters | Circle Wallets adapter | | --- | --- | --- | | Arbitrum Sepolia | ✅ | ✅ | | Arc Testnet | ✅ | ✅ | | Avalanche Fuji | ✅ | ✅ | | Base Sepolia | ✅ | ✅ | | Codex Testnet | ✅ | ❌ | | EDGE Testnet | ✅ | ❌ | | Ethereum Sepolia | ✅ | ✅ | | HyperEVM Testnet | ✅ | ❌ | | Ink Testnet | ✅ | ❌ | | Linea Sepolia | ✅ | ❌ | | Monad Testnet | ✅ | ❌ | | Morph Testnet | ✅ | ❌ | | OP Sepolia | ✅ | ✅ | | Plume Testnet | ✅ | ❌ | | Polygon PoS Amoy | ✅ | ✅ | | Sei Testnet | ✅ | ❌ | | Solana Devnet | ✅ | ✅ | | Sonic Testnet | ✅ | ❌ | | Unichain Sepolia | ✅ | ✅ | | World Chain Sepolia | ✅ | ❌ | | XDC Apothem | ✅ | ❌ | [​](https://docs.arc.network/app-kit/references/supported-blockchains#supported-tokens) Supported tokens ----------------------------------------------------------------------------------------------------------- You can specify either a contract address or an [alias](https://docs.arc.network/app-kit/references/supported-blockchains#token-aliases) for any supported token. Each App Kit capability supports different tokens: * **Send**: Any token. Use [token aliases](https://docs.arc.network/app-kit/references/supported-blockchains#token-aliases) for common tokens or the token’s contract address for other tokens. * **Bridge**: USDC only. * **Swap**: * Any tokens with enough liquidity to trade with major stablecoins such as USDC, EURC, USDT, USDe, DAI, and PYUSD. * Native tokens on blockchains where Swap is supported. * On Arc Testnet, only USDC and EURC. ### [​](https://docs.arc.network/app-kit/references/supported-blockchains#token-aliases) Token aliases App Kit works with any supported token when you supply the contract address. For convenience, you can use the following aliases for the most common tokens instead: * `USDC` * `EURC` * `USDT` * `USDe` * `DAI` * `PYUSD` * `NATIVE`: Uses the blockchain’s native token. Was this page helpful? YesNo [Installation](https://docs.arc.network/app-kit/tutorials/installation) [Adapter setups](https://docs.arc.network/app-kit/tutorials/adapter-setups) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Install App Kit - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/installation#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Get started Install App Kit [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) To get started with App Kit, install the core package and the adapter that fits your environment. To [swap](https://docs.arc.network/app-kit/swap) , you need a (free) kit key from [Circle Console](https://console.circle.com/) . 1 [](https://docs.arc.network/app-kit/tutorials/installation#) Install the core package npm yarn npm install @circle-fin/app-kit Need a lighter install? Individual packages are available App Kit lets you access all its capabilities in a single package. If you prefer to just install the capabilities you need, you can install the standalone packages: npm yarn ## Bridge npm install @circle-fin/bridge-kit ## Swap npm install @circle-fin/swap-kit 2 [](https://docs.arc.network/app-kit/tutorials/installation#) Install your preferred adapter * Viem * Ethers * Solana * Circle Wallets npm yarn npm install @circle-fin/adapter-viem-v2 viem npm yarn npm install @circle-fin/adapter-ethers-v6 ethers npm yarn npm install @circle-fin/adapter-solana-kit @solana/kit @solana/web3.js If bridging, you should also install an EVM adapter (Viem or Ethers). For the [Bridge Between Solana and EVM](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm) quickstart and [adapter setup](https://docs.arc.network/app-kit/tutorials/adapter-setups#solana) examples, the same adapter is used with `@solana/kit` and `@solana/web3.js`. server-side onlyIf you have a [Circle Wallets](https://developers.circle.com/wallets) account, you can use the Circle Wallets adapter to connect to developer-controlled wallets and Circle Contracts. npm yarn npm install @circle-fin/adapter-circle-wallets Was this page helpful? YesNo [App Kit overview](https://docs.arc.network/app-kit) [Supported blockchains and tokens](https://docs.arc.network/app-kit/references/supported-blockchains) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How bridge fees work - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/concepts/bridge-fees#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation References How bridge fees work [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Fees breakdown](https://docs.arc.network/app-kit/concepts/bridge-fees#fees-breakdown) * [Funds flow](https://docs.arc.network/app-kit/concepts/bridge-fees#funds-flow) * [Best practices for custom fees](https://docs.arc.network/app-kit/concepts/bridge-fees#best-practices-for-custom-fees) This guide explains which fees apply when bridging, how funds move through a transaction, and the best practices to follow when [implementing custom fees](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee) . [​](https://docs.arc.network/app-kit/concepts/bridge-fees#fees-breakdown) Fees breakdown ------------------------------------------------------------------------------------------- Every bridge transfer can incur the following fees: * **Your custom fee**: The extra amount you charge on top of the bridge transfer. Arc keeps 10% of this amount. The remaining 90% goes to the fee recipient you configure on the source blockchain. * **CCTP protocol fee**: For Fast Transfers only, [CCTP](https://developers.circle.com/cctp) collects a fee that varies by source chain. Standard Transfers (`SLOW` speed) do not incur this fee. For current fee rates, see [CCTP Fees](https://developers.circle.com/cctp/technical-guide#fees) . For how to configure the transfer speed, see [Configure Transfer Speed and Maximum Cost](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed) . * **CCTP Forwarding Service fee**: When you [use the Forwarding Service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) to submit the mint transaction on the destination chain, it collects a [service fee](https://developers.circle.com/cctp/concepts/forwarding-service#fees-and-execution) . [​](https://docs.arc.network/app-kit/concepts/bridge-fees#funds-flow) Funds flow ----------------------------------------------------------------------------------- The following example shows what happens when a user initiates a 1,000 USDC Fast Transfer with a 1% custom fee and the [Forwarding Service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) enabled: 1. The user initiates a 1000 USDC bridge transfer on the source blockchain. 2. You add a 10 USDC (1%) custom fee. 3. The source wallet signs a transaction for 1,010 USDC (bridge amount + custom fee). 4. The 10 USDC custom fee is split on the source blockchain: * Arc receives 1 USDC (10%). * Your fee recipient receives 9 USDC (remaining 90%). 5. The 1000 USDC bridge amount is forwarded to CCTP. 6. CCTP takes a protocol fee (0.10 USDC in this example) for a Fast Transfer. 7. The Forwarding Service deducts its fee (0.20 USDC in this example) from the amount to be minted on the destination chain. 8. The destination wallet receives 999.70 USDC on the destination chain. This flow is illustrated in the following diagram: [​](https://docs.arc.network/app-kit/concepts/bridge-fees#best-practices-for-custom-fees) Best practices for custom fees --------------------------------------------------------------------------------------------------------------------------- Follow these best practices when implementing custom fees: * Treat the custom fee as an amount added on top of the bridge transfer. Do not subtract it from the bridge amount. * Validate that the user’s wallet balance covers both the bridge amount and the custom fee. The following code shows an example balance check: TypeScript const requiredBalance = parseFloat(amount) + parseFloat(customFee); if (userBalance < requiredBalance) { throw new Error(`Insufficient balance. Need ${requiredBalance} USDC`); } * Use a fee recipient address on the source blockchain. Do not use an address on the destination. * In your UI, display the following to the user before they confirm the transaction: * The total source wallet debit: bridge amount + custom fee * The full fee breakdown: bridge amount, custom fee, CCTP Fast Transfer fee (if applicable), and Forwarding Service fee (if using the [Forwarding Service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) ) * Return human-readable decimal strings. For example, `10` rather than `10000000` for 10 USDC. App Kit handles base-unit conversion internally. Was this page helpful? YesNo [Specify a recipient address](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address) [Error recovery](https://docs.arc.network/app-kit/references/bridge-error-recovery) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # App Kit: Bridge - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/bridge#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Bridge App Kit: Bridge [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Quick look](https://docs.arc.network/app-kit/bridge#quick-look) * [Installation](https://docs.arc.network/app-kit/bridge#installation) [App Kit](https://docs.arc.network/app-kit) includes the Bridge capability that lets you move USDC across blockchains in a few lines of code. If you only need bridging and don’t want the full App Kit, you can [install](https://docs.arc.network/app-kit/bridge#installation) the Bridge package on its own. [​](https://docs.arc.network/app-kit/bridge#quick-look) Quick look --------------------------------------------------------------------- This example bridges between an EVM and non-EVM chain in a single method call: TypeScript // Transfer 1.00 USDC from Solana to Arc const result = await kit.bridge({ from: { adapter: solanaAdapter, chain: "Solana_Devnet" }, to: { adapter: viemAdapter, chain: "Arc_Testnet" }, amount: "1.00", }); [​](https://docs.arc.network/app-kit/bridge#installation) Installation ------------------------------------------------------------------------- App Kit comes with the Bridge capability installed by default. If you’ve already [installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) , you can skip this section. If you only need to bridge and don’t want the full App Kit, you can follow the steps below to install just the Bridge package. Install the Bridge package and the adapter that matches your environment: 1 [](https://docs.arc.network/app-kit/bridge#) Install the Bridge package npm yarn npm install @circle-fin/bridge-kit 2 [](https://docs.arc.network/app-kit/bridge#) Install adapters Install the [adapters](https://docs.arc.network/app-kit/tutorials/adapter-setups) you need for the chains you plan to bridge between. * Viem * Ethers * Solana * Circle Wallets npm yarn npm install @circle-fin/adapter-viem-v2 viem npm yarn npm install @circle-fin/adapter-ethers-v6 ethers npm yarn npm install @circle-fin/adapter-solana-kit solana npm yarn npm install @circle-fin/adapter-circle-wallets Was this page helpful? YesNo [Send tokens across wallets](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain) [Bridge between EVM chains](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Consensus layer - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/consensus-layer#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Network Consensus layer [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Core properties](https://docs.arc.network/arc/concepts/consensus-layer#core-properties) * [Proof-of-authority validator set](https://docs.arc.network/arc/concepts/consensus-layer#proof-of-authority-validator-set) * [How Tendermint consensus works in Malachite](https://docs.arc.network/arc/concepts/consensus-layer#how-tendermint-consensus-works-in-malachite) * [Deterministic finality](https://docs.arc.network/arc/concepts/consensus-layer#deterministic-finality) * [Performance characteristics](https://docs.arc.network/arc/concepts/consensus-layer#performance-characteristics) * [Multi-proposer](https://docs.arc.network/arc/concepts/consensus-layer#multi-proposer) * [Security guarantees](https://docs.arc.network/arc/concepts/consensus-layer#security-guarantees) * [Developer implications](https://docs.arc.network/arc/concepts/consensus-layer#developer-implications) * [Roadmap](https://docs.arc.network/arc/concepts/consensus-layer#roadmap) Arc’s consensus protocol provides deterministic finality in under one second. It is built on Malachite, a high-performance implementation of the Tendermint Byzantine Fault Tolerant (BFT) protocol, and uses a Proof-of-Authority (PoA) validator set. As a developer, you don’t interact with consensus directly, but it defines the guarantees you can rely on when building payment, trading, or settlement applications. [​](https://docs.arc.network/arc/concepts/consensus-layer#core-properties) Core properties --------------------------------------------------------------------------------------------- Arc consensus is designed for institutional-grade performance and trust: * **Deterministic finality:** A transaction is either unconfirmed or final. Once finalized, it cannot be reversed or reorganized. * **Low latency:** Blocks finalize in less than one second under normal conditions. * **High throughput:** Benchmarks show 3,000+ TPS with 20 validators and sub-second latency. Smaller validator sets can reach 10,000+ TPS. * **Validator accountability:** Validators are regulated institutions with operational and compliance obligations. * **Optimistic responsiveness:** The Tendermint protocol implemented by Malachite ensures block production and transaction confirmation proceeds as fast as the network permits, with no extra timeouts or artificial delays. [​](https://docs.arc.network/arc/concepts/consensus-layer#proof-of-authority-validator-set) Proof-of-authority validator set ------------------------------------------------------------------------------------------------------------------------------- Arc uses a **permissioned Proof-of-Authority (PoA)** model. * **Validators** are selected, known institutions with reputations, compliance requirements, and operational guarantees (such as uptime SLAs and SOC 2 certification). * **Geographic distribution** ensures resilience. Validators run across multiple global regions. * **Block production** is rotated among validators to ensure fairness and liveness. This design provides stronger assurances for regulated finance by replacing anonymous economic incentives with institutional accountability. [​](https://docs.arc.network/arc/concepts/consensus-layer#how-tendermint-consensus-works-in-malachite) How Tendermint consensus works in Malachite ----------------------------------------------------------------------------------------------------------------------------------------------------- To order and finalize transactions, Arc uses the Tendermint BFT consensus protocol, implemented in the Malachite consensus layer. At a higher level, Tendermint works as follows: 1. **Propose** * One validator is chosen as proposer for a round. * The proposer bundles transactions into a block and broadcasts it. 2. **Pre-vote** * Validators broadcast votes indicating whether they consider the block valid. 3. **Pre-commit** * Validators broadcast a second round of votes. * If more than two-thirds of validators pre-commit to the same block, that block gets committed. 4. **Commit** * The block is finalized and appended to the chain. * Transactions inside the block are now irreversible. This two-phase voting process ensures consensus safety: two conflicting blocks cannot both be finalized. As a result, block reorganizations are impossible, and each block is finalized quickly and deterministically. The diagram below illustrates the high-level concept behind this process. [​](https://docs.arc.network/arc/concepts/consensus-layer#deterministic-finality) Deterministic finality ----------------------------------------------------------------------------------------------------------- Unlike probabilistic models (like proof-of-work), Arc provides certainty about finality. * Once a block is finalized, it cannot be reverted without collusion of at least two-thirds of validators. * There is no need for developers to wait for multiple confirmations. * Applications can release funds or complete trades immediately after confirmation. For developers, this reduces complexity since you don’t need rollback logic, and you can provide users with instant settlement guarantees. [​](https://docs.arc.network/arc/concepts/consensus-layer#performance-characteristics) Performance characteristics --------------------------------------------------------------------------------------------------------------------- Arc is engineered for low latency and high throughput. In testnet environments, you can expect performance characteristics similar to the following: * **3,000 TPS** with 20 globally distributed validators. * **<350 ms** finality under benchmark conditions. * **\>10,000 TPS** with reduced validator counts (for example, 4 validators). * **Future roadmap** includes multi-proposer support (see below), which can increase throughput by ~10X, and consensus optimizations that can cut latency by ~30%. These metrics make Arc suitable for high-frequency payments, trading, and settlement systems. [​](https://docs.arc.network/arc/concepts/consensus-layer#multi-proposer) Multi-proposer ------------------------------------------------------------------------------------------- The Malachite roadmap includes a planned upgrade called multi-proposer. This feature allows multiple validators in the network to propose blocks in parallel, rather than sequentially. By enabling concurrent block proposals, multi-proposer can significantly increase network throughput and improve overall scalability. [​](https://docs.arc.network/arc/concepts/consensus-layer#security-guarantees) Security guarantees ----------------------------------------------------------------------------------------------------- Arc combines protocol-level safety with institutional safeguards: * **Safety:** With <1/3 faulty validators, consensus guarantees no conflicting blocks can be finalized. * **Liveness:** The system continues to make progress as long as ≥2/3 of validators are online and honest. * **Accountability:** Validators are regulated institutions with compliance obligations, making malicious behavior costly in the real world. * **Resilience:** Geographic distribution reduces correlated downtime and attack risk. [​](https://docs.arc.network/arc/concepts/consensus-layer#developer-implications) Developer implications ----------------------------------------------------------------------------------------------------------- For developers, consensus guarantees that: * Your transactions settle instantly and irreversibly. * You don’t need to design around chain reorganizations or probabilistic confirmations. * Arc can handle institutional workloads with high TPS and low latency. * Validator accountability ensures the network remains secure and compliant, even at scale. [​](https://docs.arc.network/arc/concepts/consensus-layer#roadmap) Roadmap ----------------------------------------------------------------------------- Malachite continues to evolve: * **Multi-proposer support:** Multiple proposers per height increase overall throughput. * **Latency optimizations:** New protocol variant reduces consensus rounds from three to two. * **Permissioned Proof-of-Stake transition:** Over time, Arc may evolve from PoA to a permissioned PoS model, allowing broader validator participation while maintaining compliance. These upgrades will further strengthen Arc as infrastructure for global financial applications. Was this page helpful? YesNo [Contract addresses](https://docs.arc.network/arc/references/contract-addresses) [Execution layer](https://docs.arc.network/arc/concepts/execution-layer) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How to: Configure transfer speed and maximum cost - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize bridging How to: Configure transfer speed and maximum cost [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed#prerequisites) * [Configure slow speed](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed#configure-slow-speed) * [Configure maximum fee](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed#configure-maximum-fee) By default, App Kit uses CCTP’s [Fast Transfer](https://developers.circle.com/cctp) feature to optimize for speed. However, [this can incur higher fees](https://developers.circle.com/cctp/technical-guide#fees) . If performance is not a concern, you can specify a slow transfer speed, which uses CCTP’s Standard Transfer feature. To balance performance and cost, you can set the maximum fee you want to pay on fast bridge transfers. The transfer switches to slow if the cost is above your limit. [​](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed#prerequisites) Prerequisites -------------------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed#configure-slow-speed) Configure slow speed ---------------------------------------------------------------------------------------------------------------------------- This code configures a slow transfer speed: TypeScript // Slow transfer speed const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet" }, amount: "1.00", config: { transferSpeed: "SLOW" }, // Slow transfer speed }); [​](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed#configure-maximum-fee) Configure maximum fee ------------------------------------------------------------------------------------------------------------------------------ Set the maximum fee that you want to pay for the CCTP fast burn. This code configures a maximum fee of 0.10 USDC: TypeScript const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet", }, amount: "1.00", config: { transferSpeed: "FAST", // Fast transfer speed (can be omitted) maxFee: "0.10", // Max 0.10 USDC fee }, }); Was this page helpful? YesNo [Use forwarding service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) [Specify a recipient address](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How to: Collect custom swap fees - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize swapping How to: Collect custom swap fees [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee#prerequisites) * [Set a custom fee on a swap](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee#set-a-custom-fee-on-a-swap) You can configure your swaps to collect a custom fee from end users on each swap call. For how custom fees fit into the overall fees breakdown, see [How Swap Fees Work](https://docs.arc.network/app-kit/concepts/swap-fees) . If you use this feature, Arc keeps 10% of the custom fee you collect from your end users. [​](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee#prerequisites) Prerequisites ---------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee#set-a-custom-fee-on-a-swap) Set a custom fee on a swap ------------------------------------------------------------------------------------------------------------------------------ This example adds a 1% (100 basis points) fee to a single swap call: TypeScript const output = await kit.swap({ from: { adapter, chain: "Arc_Testnet" }, tokenIn: "USDC", amountIn: "1.00", tokenOut: "EURC", config: { kitKey: process.env.KIT_KEY as string, customFee: { percentageBps: 100, // 1% fee recipientAddress: "YOUR_WALLET_ADDRESS", }, }, }); Was this page helpful? YesNo [Swap tokens on a chain](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain) [Estimate swap rate](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Arc Network - Arc Docs [Skip to main content](https://docs.arc.network/arc-chain#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Arc Network [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Key features](https://docs.arc.network/arc-chain#key-features) * [Network architecture](https://docs.arc.network/arc-chain#network-architecture) * [Stablecoins on Arc](https://docs.arc.network/arc-chain#stablecoins-on-arc) * [Network details](https://docs.arc.network/arc-chain#network-details) * [Start building](https://docs.arc.network/arc-chain#start-building) Arc is an EVM-compatible Layer-1 blockchain designed for onchain finance. It combines [predictable fiat-based fees](https://docs.arc.network/arc/concepts/stable-fee-design) using stablecoins as gas, [sub-second deterministic finality](https://docs.arc.network/arc/concepts/deterministic-finality) , and [opt-in configurable privacy](https://docs.arc.network/arc/concepts/opt-in-privacy) to support payments, lending, capital markets, and FX at scale. [​](https://docs.arc.network/arc-chain#key-features) Key features -------------------------------------------------------------------- Arc is purpose-built for real-world economic activity, not general-purpose computation. Each design choice directly supports the needs of financial applications. Stable fee design ----------------- Transaction fees are denominated in USDC, so costs stay predictable regardless of token volatility. Deterministic finality ---------------------- Transactions finalize in under one second with no risk of chain reorganization. Opt-in privacy -------------- Confidential transfers and selective disclosure for regulated use cases, available when you need them. EVM compatibility ----------------- Deploy existing Solidity contracts and use standard Ethereum tooling like Hardhat, Foundry, and Viem. [​](https://docs.arc.network/arc-chain#network-architecture) Network architecture ------------------------------------------------------------------------------------ Arc separates consensus from execution so each layer can optimize independently while maintaining full compatibility with the Ethereum ecosystem. * **[Consensus layer](https://docs.arc.network/arc/concepts/consensus-layer) **: Built on Malachite, a BFT consensus engine designed for sub-second finality and high throughput. A permissioned validator set provides security and compliance guarantees while keeping the network open for developers and users. * **[Execution layer](https://docs.arc.network/arc/concepts/execution-layer) **: Runs the EVM, so Solidity contracts, development tools, and wallet infrastructure work without modification. For a complete view of how the layers interact, see the [system overview](https://docs.arc.network/arc/concepts/system-overview) . [​](https://docs.arc.network/arc-chain#stablecoins-on-arc) Stablecoins on Arc -------------------------------------------------------------------------------- USDC is the native [gas token](https://docs.arc.network/arc/references/gas-and-fees) on Arc, so transaction fees are denominated in dollars and you don’t need to hold or manage a separate token to transact. The base fee targets $0.01 per transaction and uses an [EIP-1559-style smoothing mechanism](https://docs.arc.network/arc/concepts/stable-fee-design) to keep costs predictable even under varying network load. Arc also supports EURC for euro-denominated transfers. Both USDC and EURC are available on the [Circle Faucet](https://faucet.circle.com/) for testnet development, and their contract addresses are listed on the [contract addresses](https://docs.arc.network/arc/references/contract-addresses) page. [​](https://docs.arc.network/arc-chain#network-details) Network details -------------------------------------------------------------------------- | **Property** | **Value** | | --- | --- | | Consensus | Malachite BFT | | Execution environment | EVM | | Gas token | USDC | | Finality | Deterministic, sub-second | | Validator participation | Permissioned | | Developer access | Permissionless | For RPC endpoints, chain ID, and connection details, see [Connect to Arc](https://docs.arc.network/arc/references/connect-to-arc) . For deployed contract addresses, see [contract addresses](https://docs.arc.network/arc/references/contract-addresses) . [​](https://docs.arc.network/arc-chain#start-building) Start building ------------------------------------------------------------------------ Ready to build on Arc? Head to the [Build](https://docs.arc.network/arc/tutorials/deploy-on-arc) section for quickstarts and tutorials covering smart contract deployment, stablecoin transfers, crosschain bridging, and AI agent integration. Was this page helpful? YesNo [Deterministic finality and settlement](https://docs.arc.network/arc/concepts/deterministic-finality) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How-to: Estimate swap rate - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize swapping How-to: Estimate swap rate [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate#prerequisites) * [Estimate swap amount](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate#estimate-swap-amount) You can get a pre-swap estimate of the amount you’ll receive before swapping. [​](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------------ Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate#estimate-swap-amount) Estimate swap amount -------------------------------------------------------------------------------------------------------------------- This example estimates how much EURC you’ll receive when swapping 1.00 USDC for EURC: TypeScript // Set up the swap const params = { from: { adapter, chain: "Arc_Testnet" }, tokenIn: "USDC", amountIn: "1.00", tokenOut: "EURC", config: { kitKey: process.env.KIT_KEY as string, }, }; // Estimate swap amount const estimate = await kit.estimateSwap(params); console.log(`Estimated output: ${estimate.estimatedOutput}`); // Proceed to swap const result = await kit.swap(params); Was this page helpful? YesNo [Collect custom swap fees](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee) [Set slippage tolerance or stop limit](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How to: Use the CCTP forwarding service - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize bridging How to: Use the CCTP forwarding service [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#prerequisites) * [Use with adapters on both chains](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#use-with-adapters-on-both-chains) * [Use without a destination adapter](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#use-without-a-destination-adapter) * [Forwarding fee](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#forwarding-fee) You can use the [CCTP Forwarding Service](https://developers.circle.com/cctp/concepts/forwarding-service) on bridge transfers. When enabled, it fetches the attestation and submits the mint on the destination chain. You don’t need to poll for attestations or have access to a wallet on the destination chain. [​](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------------------ Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#use-with-adapters-on-both-chains) Use with adapters on both chains -------------------------------------------------------------------------------------------------------------------------------------------------- Set `useForwarder: true` when you have adapters for both chains but want the Forwarding Service to submit the mint transaction on the destination: TypeScript const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet", useForwarder: true, }, amount: "1.00", }); [​](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#use-without-a-destination-adapter) Use without a destination adapter ---------------------------------------------------------------------------------------------------------------------------------------------------- When you don’t have access to a wallet on the destination chain, such as with server-side or custodial bridge flows, omit the destination adapter and pass `recipientAddress` with `useForwarder: true`: TypeScript const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { recipientAddress: "RECIPIENT_ADDRESS", chain: "Arc_Testnet", useForwarder: true, }, amount: "1.00", }); In this mode, mint confirmation comes from the Circle Iris API response rather than an onchain receipt. Because the Forwarding Service submits the mint transaction, no locally signed transaction hash is returned and the mint step’s `data` field is `undefined`. [​](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service#forwarding-fee) Forwarding fee -------------------------------------------------------------------------------------------------------------- The Forwarding Service charges a [fee](https://developers.circle.com/cctp/concepts/forwarding-service#fees-and-execution) that is deducted from the amount minted on the destination chain. When you [estimate costs](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs) for a bridge transfer, the result includes the forwarding fee. See [How Bridge Fees Work](https://docs.arc.network/app-kit/concepts/bridge-fees) for details. Was this page helpful? YesNo [Estimate costs](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs) [Configure transfer speed and maximum cost](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How to: Estimate costs before bridging - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize bridging How to: Estimate costs before bridging [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs#prerequisites) * [Estimate costs](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs#estimate-costs) App Kit can estimate gas fees and provider fees before making a bridge transfer, and only proceed if the costs are acceptable. [​](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs#prerequisites) Prerequisites ---------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs#estimate-costs) Estimate costs ------------------------------------------------------------------------------------------------------ This example estimates costs for a bridge transfer of 1.00 USDC from Ethereum Sepolia to Arc Testnet: TypeScript import type { BridgeParams } from "@circle-fin/app-kit"; const params: BridgeParams = { from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet" }, amount: "1.00", }; // Estimate costs const estimate = await kit.estimateBridge(params); console.log( `Estimating ${params.amount} USDC from ${params.from.chain} to ${params.to.chain}`, ); console.log("Estimated fees:", estimate.fees); const providerFee = estimate.fees.find( (fee) => fee.type === "provider", )?.amount; // Only proceed if the provider fee is less than 0.10 USDC // Also proceed if the `providerFee` variable is null/undefined since there is no provider fee to charge if (providerFee == null || parseFloat(providerFee) < 0.1) { // Execute the bridge transfer const result = await kit.bridge(params); console.log("Bridge transfer completed:", result); } else { // Provider fee is 0.10 USDC or higher - abort the bridge transfer console.log("Provider fee is above threshold:", providerFee, "USDC"); } Was this page helpful? YesNo [Collect custom bridge fees](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee) [Use forwarding service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How to: Specify a recipient address - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize bridging How to: Specify a recipient address [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address#prerequisites) * [Specify a recipient](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address#specify-a-recipient) By default, bridged USDC arrives at the same address as your signing wallet on the destination chain. For bridge transfers, you can specify a recipient address so the tokens are minted to that address instead. [​](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address#prerequisites) Prerequisites --------------------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address#specify-a-recipient) Specify a recipient --------------------------------------------------------------------------------------------------------------------------- This example bridges 1.00 USDC from your wallet address on Ethereum Sepolia to a different address on Arc Testnet: TypeScript // Send from your wallet address to a different recipient address on the destination chain const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet", recipientAddress: "RECIPIENT_ADDRESS", // Specify a recipient address }, amount: "1.00", }); Was this page helpful? YesNo [Configure transfer speed and maximum cost](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed) [How bridge fees work](https://docs.arc.network/app-kit/concepts/bridge-fees) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Quickstart: Send tokens across wallets on the same blockchain - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Send Quickstart: Send tokens across wallets on the same blockchain [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#prerequisites) * [Step 1. Set up the project](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#step-1-set-up-the-project) * [1.1. Set up your development environment](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#1-1-set-up-your-development-environment) * [1.2. Configure TypeScript (optional)](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#1-2-configure-typescript-optional) * [1.3. Configure environment variables](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#1-3-configure-environment-variables) * [Step 2. Send tokens to recipient](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#step-2-send-tokens-to-recipient) * [2.1. Create the script](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#2-1-create-the-script) * [2.2. Run the script](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#2-2-run-the-script) * [2.3. Verify the transaction](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#2-3-verify-the-transaction) * [Next steps](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#next-steps) 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](https://docs.arc.network/app-kit/references/supported-blockchains) . [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * Installed [Node.js v22+](https://nodejs.org/) . * Created an [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) wallet and funded it with testnet USDC and testnet native tokens. [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#step-1-set-up-the-project) Step 1. Set up the project -------------------------------------------------------------------------------------------------------------------------------- This step shows you how to prepare your project and environment. ### [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#1-1-set-up-your-development-environment) 1.1. Set up your development environment Create a new directory and install App Kit and its dependencies: Shell # Set up your directory and initialize a Node.js project mkdir app-kit-quickstart-send cd app-kit-quickstart-send npm init -y # Install App Kit and tools npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem typescript tsx ### [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell npx tsc --init Then, update the `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#1-3-configure-environment-variables) 1.3. Configure environment variables Create an `.env` file in the project directory: Shell touch .env Then, add your wallet private key. Replace `YOUR_PRIVATE_KEY` with the private key for your wallet: .env PRIVATE_KEY=YOUR_PRIVATE_KEY Edit `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#step-2-send-tokens-to-recipient) Step 2. Send tokens to recipient -------------------------------------------------------------------------------------------------------------------------------------------- This step shows you how to set up your script, send tokens from your wallet to a recipient on the same blockchain, and check the result. ### [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#2-1-create-the-script) 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 wallet to a recipient on Arc Testnet: Using another [token](https://docs.arc.network/app-kit/references/supported-blockchains#supported-tokens) or [blockchain](https://docs.arc.network/app-kit/references/supported-blockchains) ? Change the `token` and `chain` values in `kit.send()` and use an adapter for that chain. TypeScript import { AppKit } from "@circle-fin/app-kit"; import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import type { SendParams } from "@circle-fin/app-kit"; import { inspect } from "node:util"; const kit = new AppKit(); const sendTokens = async (): Promise => { const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); const sendParams: SendParams = { from: { adapter, chain: "Arc_Testnet" }, to: "RECIPIENT_ADDRESS", // Replace with recipient address amount: "1.00", token: "USDC", }; const estimate = await kit.estimateSend(sendParams); const result = await kit.send(sendParams); console.log(inspect(result, false, null, true)); }; void sendTokens(); ### [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#2-2-run-the-script) 2.2. Run the script Save the `index.ts` file and run the script in your terminal: Shell npx tsx --env-file=.env index.ts ### [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#2-3-verify-the-transaction) 2.3. Verify the transaction After the script finishes, find 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: Shell { name: "transfer", state: "success", txHash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", explorerUrl: "https://testnet.arcscan.app/tx/0x1234567890abcdef..." } [​](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain#next-steps) Next steps ------------------------------------------------------------------------------------------------- * Review the [Send overview](https://docs.arc.network/app-kit/send) for more on the Send capability. * Try [Bridge](https://docs.arc.network/app-kit/bridge) or [Swap](https://docs.arc.network/app-kit/swap) to move value across chains or swap tokens on the same chain. * See [Adapter setups](https://docs.arc.network/app-kit/tutorials/adapter-setups) to use different wallet adapters, or the [SDK reference](https://docs.arc.network/app-kit/references/sdk-reference) for the full API. Was this page helpful? YesNo [Send overview](https://docs.arc.network/app-kit/send) [Bridge overview](https://docs.arc.network/app-kit/bridge) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How to: Collect custom bridge fees - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize bridging How to: Collect custom bridge fees [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee#prerequisites) * [Set a custom fee on a bridge](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee#set-a-custom-fee-on-a-bridge) App Kit lets you collect a custom fee from your end users on each bridge transfer. For how custom fees fit into the overall fees breakdown, see [How Bridge Fees Work](https://docs.arc.network/app-kit/concepts/bridge-fees) . If you use this feature, Arc keeps 10% of the custom fee you collect from your end users. [​](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee#prerequisites) Prerequisites -------------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee#set-a-custom-fee-on-a-bridge) Set a custom fee on a bridge -------------------------------------------------------------------------------------------------------------------------------------- This example adds a 0.10 USDC fee to a single bridge transfer: TypeScript // Bridge 1.00 USDC from Ethereum to Arc const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet" }, amount: "1.00", // Collect a fee of 0.10 USDC on this bridge transfer config: { customFee: { value: "0.10", recipientAddress: "YOUR_WALLET_ADDRESS", }, }, }); Was this page helpful? YesNo [Bridge with Circle Wallets](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets) [Estimate costs](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # App Kit - Arc Docs [Skip to main content](https://docs.arc.network/app-kit#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation App Kit App Kit [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Quick install](https://docs.arc.network/app-kit#quick-install) * [Core capabilities](https://docs.arc.network/app-kit#core-capabilities) * [Key benefits](https://docs.arc.network/app-kit#key-benefits) * [Quick look](https://docs.arc.network/app-kit#quick-look) The Arc App Kit SDK lets you build apps for common payment and liquidity workflows across blockchains. You can add its [capabilities](https://docs.arc.network/app-kit#core-capabilities) to your app in just a few lines of code. It provides a type-safe interface that works with Viem, Ethers, Solana Web3.js, and Circle Wallets so you can use your existing wallet infrastructure to build new apps. You can also extend the kit to support other wallet providers and frameworks. [​](https://docs.arc.network/app-kit#quick-install) Quick install -------------------------------------------------------------------- To get started quickly, install the core package and the Viem adapter: npm yarn npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem Need a different adapter or standalone packages? See the full [installation](https://docs.arc.network/app-kit/tutorials/installation) guide. [​](https://docs.arc.network/app-kit#core-capabilities) Core capabilities ---------------------------------------------------------------------------- Combine and use any of App Kit’s core capabilities in your app. Bridge ------ Transfer USDC across blockchains. Swap ---- Exchange one token for another on the same blockchain. Send ---- Transfer tokens between wallets on the same blockchain. [​](https://docs.arc.network/app-kit#key-benefits) Key benefits ------------------------------------------------------------------ * **Simple setup**: Get up and running with minimal configuration and a few lines of code. * **Application monetization**: Collect a custom fee from end users without writing new code. * **Flexible configurations**: Specify custom RPC endpoints and wallet clients. * **Broad compatibility**: Works with Viem, Ethers, Solana, and Circle Wallets, integrating smoothly with existing developer workflows. [​](https://docs.arc.network/app-kit#quick-look) Quick look -------------------------------------------------------------- The following examples show how each capability can be integrated with a single method call. * Bridge * Swap * Send TypeScript // Transfer 1.00 USDC from Ethereum to Arc const result = await kit.bridge({ from: { adapter: viemAdapter, chain: "Ethereum_Sepolia" }, to: { adapter: viemAdapter, chain: "Arc_Testnet" }, amount: "1.00", }); Ready to start bridging? Follow the quickstart for your environment: * [Bridge Between EVM Chains](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains) * [Bridge Between Solana and EVM](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm) * [Bridge with Circle Wallets](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets) TypeScript // Swap 1.00 USDC for EURC on Arc Testnet const result = await kit.swap({ from: { adapter: viemAdapter, chain: "Arc_Testnet" }, tokenIn: "USDC", tokenOut: "EURC", amountIn: "1.00", config: { kitKey: process.env.KIT_KEY as string, // Your kit key from the Circle Console }, }); Ready to start swapping? Follow the quickstart: [Swap Tokens on a Blockchain](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain) . TypeScript // Send 1.00 USDC from one wallet to another on Arc Testnet const result = await kit.send({ from: { adapter, chain: "Arc_Testnet" }, to: "RECIPIENT_ADDRESS", amount: "1.00", token: "USDC", }); Ready to start sending tokens? Follow the quickstart: [Send Tokens Across Wallets](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain) . Want to combine capabilities? Follow the [Swap Tokens Across Chains](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain) quickstart to swap and bridge tokens in the same flow. Was this page helpful? YesNo [Create your first ERC-8183 job](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job) [Installation](https://docs.arc.network/app-kit/tutorials/installation) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Quickstart: Swap tokens on a blockchain - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Swap Quickstart: Swap tokens on a blockchain [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#prerequisites) * [Step 1. Set up the project](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#step-1-set-up-the-project) * [1.1. Set up your development environment](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#1-1-set-up-your-development-environment) * [1.2. Configure TypeScript (optional)](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#1-2-configure-typescript-optional) * [1.3. Configure environment variables](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#1-3-configure-environment-variables) * [Step 2. Perform the swap](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#step-2-perform-the-swap) * [2.1. Create the script](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#2-1-create-the-script) * [2.2. Run the script](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#2-2-run-the-script) * [2.3. Verify the transaction](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#2-3-verify-the-transaction) This quickstart walks you through how to use App Kit’s [Swap](https://docs.arc.network/app-kit/swap) capability to swap tokens on the same blockchain. The example swaps USDC for EURC on Arc Testnet, but you can use other [supported tokens or blockchains](https://docs.arc.network/app-kit/references/supported-blockchains) . [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#prerequisites) 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 [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) . * Funded the wallet with testnet USDC and native tokens for fees from the [Circle Faucet](https://faucet.circle.com/) . * Obtained a (free) kit key from [Circle Console](https://console.circle.com/) . [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#step-1-set-up-the-project) Step 1. Set up the project -------------------------------------------------------------------------------------------------------------------------------- This step shows you how to prepare your project and environment. ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#1-1-set-up-your-development-environment) 1.1. Set up your development environment Create a new directory and install App Kit and its dependencies: Shell # Set up your directory and initialize a Node.js project mkdir app-kit-quickstart-swap cd app-kit-quickstart-swap npm init -y # Install App Kit and tools npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem typescript tsx Only need to swap and want a lighter install than the full App Kit? Install the standalone swap package instead: `@circle-fin/swap-kit` ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell npx tsc --init Then, update the `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#1-3-configure-environment-variables) 1.3. Configure environment variables Create an `.env` file in the project directory: Shell touch .env Then, add your credentials. Replace `YOUR_PRIVATE_KEY` with the private key for your wallet and `YOUR_KIT_KEY` with the kit key from [Circle Console](https://console.circle.com/) : .env PRIVATE_KEY=YOUR_PRIVATE_KEY KIT_KEY=YOUR_KIT_KEY Edit `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#step-2-perform-the-swap) Step 2. Perform the swap ---------------------------------------------------------------------------------------------------------------------------- This step shows you how to set up your script, execute a swap from USDC to EURC on Arc Testnet, and check the result. ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#2-1-create-the-script) 2.1. Create the script Create an `index.ts` file in the project directory and add the following code. This code swaps 1.00 USDC for EURC on Arc Testnet: Using other [tokens](https://docs.arc.network/app-kit/references/supported-blockchains#supported-tokens) or a different [blockchain](https://docs.arc.network/app-kit/references/supported-blockchains) ? Change the `tokenIn`, `tokenOut`, and `chain` values in `kit.swap()` and use an adapter for that chain. TypeScript // Import App Kit and its dependencies import { AppKit } from "@circle-fin/app-kit"; import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { inspect } from "util"; // Initialize the SDK const kit = new AppKit(); const swapUSDCtoEURC = async (): Promise => { try { // Initialize the adapter const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); console.log("---------------Starting Swapping---------------"); const result = await kit.swap({ from: { adapter, chain: "Arc_Testnet" }, // Adapter and blockchain for the swap tokenIn: "USDC", // Token to swap tokenOut: "EURC", // Token to receive amountIn: "1.00", // Amount of tokenIn to swap (human-readable) config: { kitKey: process.env.KIT_KEY as string, // Your kit key from the Circle Console }, }); console.log("RESULT", inspect(result, false, null, true)); } catch (err) { console.log("ERROR", inspect(err, false, null, true)); } }; void swapUSDCtoEURC(); Customize your swaps to [collect a custom fee](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee) , [set a slippage tolerance or stop limit](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit) , or [get a pre-swap estimate](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate) . ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#2-2-run-the-script) 2.2. Run the script Save the `index.ts` file and run the script in your terminal: Shell npx tsx --env-file=.env index.ts ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain#2-3-verify-the-transaction) 2.3. Verify the transaction After the script finishes, find the returned result object in the terminal output. Use the `explorerUrl` to verify the swap transaction and confirm the amount matches how much EURC was received. The following code is an example of how the result of a successful swap might look in the terminal output. The values are used in this example only and are not a real transaction: Shell { tokenIn: 'USDC', tokenOut: 'EURC', chain: { chain: 'Arc_Testnet', isTestnet: true }, amountIn: '1.00', amountOut: '0.99', fromAddress: '0x1234123412341234123412341234123412341234', toAddress: '0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', txHash: '0x78abb6a896e6b166925cae122b6ab2a6abd49ba23cbbd4749c99d5cccf205897', explorerUrl: 'https://testnet.arcscan.app/tx/0x78abb6a896e6b166925cae122b6ab2a6abd49ba23cbbd4749c99d5cccf205897', fees: [ { token: 'USDC', amount: '0.001', type: 'provider' } ], config: { kitKey: 'KIT_KEY:fdd99fdbdb3c87b9b3f7b29d6cc17b6e:cc8777b4e419eb6dda9f0de932cf0bb8', } } Was this page helpful? YesNo [Swap overview](https://docs.arc.network/app-kit/swap) [Collect custom swap fees](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Quickstart: Bridge between Solana and EVM - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Quickstart: Bridge between Solana and EVM [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#prerequisites) * [Step 1. Set up the project](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#step-1-set-up-the-project) * [1.1. Set up your development environment](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#1-1-set-up-your-development-environment) * [1.2. Configure TypeScript (optional)](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#1-2-configure-typescript-optional) * [1.3. Configure environment variables](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#1-3-configure-environment-variables) * [Step 2. Bridge USDC](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#step-2-bridge-usdc) * [2.1. Create the script](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#2-1-create-the-script) * [2.2. Run the script](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#2-2-run-the-script) * [2.3. Verify the transaction](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#2-3-verify-the-transaction) This quickstart helps you write a server-side script that bridges USDC between Solana and an EVM-compatible blockchain. The examples in this quickstart use Solana Devnet and Arc Testnet, but you can use Solana and any [supported EVM chain](https://docs.arc.network/app-kit/references/supported-blockchains) as source or destination. [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#prerequisites) Prerequisites -------------------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * Installed [Node.js v22+](https://nodejs.org/) . * Created a Solana Devnet wallet and an [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) wallet using a wallet provider such as [MetaMask](https://metamask.io/) . * Funded your wallets with testnet tokens: * Get testnet USDC from the [Circle Faucet](https://faucet.circle.com/) . * Get native tokens for Solana Devnet from the [Solana Faucet](https://faucet.solana.com/) . * Get native tokens for Arc Testnet from the [Console Faucet](https://console.circle.com/faucet) . [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#step-1-set-up-the-project) Step 1. Set up the project --------------------------------------------------------------------------------------------------------------------------------------- This step shows you how to prepare your project and environment. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#1-1-set-up-your-development-environment) 1.1. Set up your development environment Create a new directory and install App Kit and its dependencies: Shell # Set up your directory and initialize the project mkdir app-kit-quickstart-bridge-solana-evm cd app-kit-quickstart-bridge-solana-evm npm init -y # Install App Kit and tools (Solana + EVM adapters) npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 @circle-fin/adapter-solana-kit @solana/kit @solana/web3.js viem typescript tsx Only need to bridge and want a lighter install than the full App Kit? Install the standalone bridge package instead: `@circle-fin/bridge-kit` ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell npx tsc --init Then, update the `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#1-3-configure-environment-variables) 1.3. Configure environment variables Create an `.env` file in the project directory: Shell touch .env Then, add your wallet private keys. Replace `YOUR_SOLANA_PRIVATE_KEY` with your Solana wallet private key and `YOUR_ARC_TESTNET_PRIVATE_KEY` with your Arc Testnet (EVM) wallet private key: .env SOLANA_PRIVATE_KEY=YOUR_SOLANA_PRIVATE_KEY EVM_PRIVATE_KEY=YOUR_ARC_TESTNET_PRIVATE_KEY If you use MetaMask, follow their guide for how to [find and export your private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/) . Edit `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#step-2-bridge-usdc) Step 2. Bridge USDC ------------------------------------------------------------------------------------------------------------------------- This step shows you how to set up your script, execute the bridge transfer, and check the result. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#2-1-create-the-script) 2.1. Create the script Create an `index.ts` file in the project directory and add the following code. This code sets up your script and bridges 1.00 USDC from Solana Devnet to Arc Testnet: Using a different EVM chain or Solana as the destination? Change the `chain` values in `kit.bridge()` and ensure your source wallet has USDC and both wallets have native tokens. TypeScript // Import App Kit and dependencies import { AppKit } from "@circle-fin/app-kit"; import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { createSolanaKitAdapterFromPrivateKey } from "@circle-fin/adapter-solana-kit"; import { inspect } from "util"; const kit = new AppKit(); const bridgeUSDC = async (): Promise => { try { const solanaAdapter = createSolanaKitAdapterFromPrivateKey({ privateKey: process.env.SOLANA_PRIVATE_KEY as string, }); const evmAdapter = createViemAdapterFromPrivateKey({ privateKey: process.env.EVM_PRIVATE_KEY as string, }); console.log("---------------Starting Bridging---------------"); const result = await kit.bridge({ from: { adapter: solanaAdapter, chain: "Solana_Devnet" }, to: { adapter: evmAdapter, chain: "Arc_Testnet" }, amount: "1.00", }); console.log("RESULT", inspect(result, false, null, true)); } catch (err) { console.log("ERROR", inspect(err, false, null, true)); } }; void bridgeUSDC(); You can customize your bridges to [collect a fee](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee) , [use the CCTP Forwarding Service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) , or [estimate gas and provider fees](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs) before bridging. Proceed only if the cost works for you. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#2-2-run-the-script) 2.2. Run the script Save the `index.ts` file and run the script in your terminal: Shell npx tsx --env-file=.env index.ts ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm#2-3-verify-the-transaction) 2.3. Verify the transaction After the script finishes, find the returned `steps` array in the terminal output. Each transaction step includes an `explorerUrl`. Use that link to verify that the USDC amount matches the amount you bridged. The following code is an example of how an `approve` step might look in the terminal output. The values are used in this example only and are not a real transaction: Shell steps: [\ {\ name: "approve",\ state: "success",\ txHash: "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ data: {\ txHash:\ "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ status: "success",\ cumulativeGasUsed: 17138643n,\ gasUsed: 38617n,\ blockNumber: 8778959n,\ blockHash:\ "0xbeadfacefeed1234567890abcdef1234567890abcdef1234567890abcdef12",\ transactionIndex: 173,\ effectiveGasPrice: 1037232n,\ explorerUrl:\ "https://testnet.arcscan.app/tx/0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ },\ },\ ]; Was this page helpful? YesNo [Bridge between EVM chains](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains) [Bridge with Circle Wallets](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Quickstart: Bridge between EVM chains - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Quickstart: Bridge between EVM chains [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#prerequisites) * [Step 1. Set up the project](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#step-1-set-up-the-project) * [1.1. Set up your development environment](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#1-1-set-up-your-development-environment) * [1.2. Configure TypeScript (optional)](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#1-2-configure-typescript-optional) * [1.3. Configure environment variables](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#1-3-configure-environment-variables) * [Step 2. Bridge USDC](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#step-2-bridge-usdc) * [2.1. Create the script](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#2-1-create-the-script) * [2.2. Run the script](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#2-2-run-the-script) * [2.3. Verify the transaction](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#2-3-verify-the-transaction) This quickstart helps you write a server-side script that bridges USDC between two EVM-compatible blockchains. The examples in this quickstart use Ethereum Sepolia and Arc Testnet, but you can use any [supported EVM chains](https://docs.arc.network/app-kit/references/supported-blockchains) as the source or destination. [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#prerequisites) 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 [Ethereum Sepolia](https://chainlist.org/chain/11155111) and [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) networks. * Funded your EVM wallet with testnet tokens: * Get testnet USDC from the [Circle Faucet](https://faucet.circle.com/) . * Get native tokens for Ethereum Sepolia from a [public faucet](https://www.alchemy.com/faucets/ethereum-sepolia) . * Get native tokens for Arc Testnet from the [Console Faucet](https://console.circle.com/faucet) . [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#step-1-set-up-the-project) Step 1. Set up the project ----------------------------------------------------------------------------------------------------------------------------------- This step shows you how to prepare your project and environment. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#1-1-set-up-your-development-environment) 1.1. Set up your development environment Create a new directory and install App Kit and its dependencies: Shell # Set up your directory and initialize a Node.js project mkdir app-kit-quickstart-bridge-evm cd app-kit-quickstart-bridge-evm npm init -y # Install App Kit and tools npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem typescript tsx Only need to bridge and want a lighter install than the full App Kit? Install the standalone bridge package instead: `@circle-fin/bridge-kit` ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell npx tsc --init Then, update the `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#1-3-configure-environment-variables) 1.3. Configure environment variables Create an `.env` file in the project directory: Shell touch .env Then, add your wallet private key. Replace `YOUR_PRIVATE_KEY` with the private key from your Ethereum Sepolia (or any EVM) wallet: .env PRIVATE_KEY=YOUR_PRIVATE_KEY If you use MetaMask, follow their guide for how to [find and export your private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/) . Edit `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#step-2-bridge-usdc) Step 2. Bridge USDC --------------------------------------------------------------------------------------------------------------------- This step shows you how to set up your script, execute the bridge transfer, and check the result. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#2-1-create-the-script) 2.1. Create the script Create an `index.ts` file in the project directory and add the following code. This code sets up your script and bridges 1.00 USDC from Ethereum Sepolia to Arc Testnet: Using other EVM chains? Change the `chain` values in `kit.bridge()` and ensure your source wallet has USDC and both wallets have native tokens. TypeScript // Import App Kit and its dependencies import { AppKit } from "@circle-fin/app-kit"; import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { inspect } from "util"; // Initialize the SDK const kit = new AppKit(); const bridgeUSDC = async (): Promise => { try { // Initialize the adapter which lets you bridge tokens from your wallet on any EVM-compatible chain const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); console.log("---------------Starting Bridging---------------"); // Use the same adapter for the source and destination blockchains const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet" }, amount: "1.00", }); console.log("RESULT", inspect(result, false, null, true)); } catch (err) { console.log("ERROR", inspect(err, false, null, true)); } }; void bridgeUSDC(); You can customize your bridges to [collect a fee](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee) , [use the CCTP Forwarding Service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) , or [estimate gas and provider fees](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs) before bridging. Proceed only if the cost works for you. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#2-2-run-the-script) 2.2. Run the script Save the `index.ts` file and run the script in your terminal: Shell npx tsx --env-file=.env index.ts ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains#2-3-verify-the-transaction) 2.3. Verify the transaction After the script finishes, find the returned `steps` array in the terminal output. Each transaction step includes an `explorerUrl`. Use that link to verify that the USDC amount matches the amount you bridged. The following code is an example of how an `approve` step might look in the terminal output. The values are used in this example only and are not a real transaction: Shell steps: [\ {\ name: "approve",\ state: "success",\ txHash: "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ data: {\ txHash:\ "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ status: "success",\ cumulativeGasUsed: 17138643n,\ gasUsed: 38617n,\ blockNumber: 8778959n,\ blockHash:\ "0xbeadfacefeed1234567890abcdef1234567890abcdef1234567890abcdef12",\ transactionIndex: 173,\ effectiveGasPrice: 1037232n,\ explorerUrl:\ "https://testnet.arcscan.app/tx/0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ },\ },\ ]; Was this page helpful? YesNo [Bridge overview](https://docs.arc.network/app-kit/bridge) [Bridge between Solana and EVM](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Error recovery and troubleshooting for bridges - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/references/bridge-error-recovery#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation References Error recovery and troubleshooting for bridges [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Bridge transfer failures](https://docs.arc.network/app-kit/references/bridge-error-recovery#bridge-transfer-failures) * [Transaction steps overview](https://docs.arc.network/app-kit/references/bridge-error-recovery#transaction-steps-overview) * [Bridge result details](https://docs.arc.network/app-kit/references/bridge-error-recovery#bridge-result-details) * [Step analysis](https://docs.arc.network/app-kit/references/bridge-error-recovery#step-analysis) * [Recovery scenarios](https://docs.arc.network/app-kit/references/bridge-error-recovery#recovery-scenarios) * [Retry a failed bridge transfer](https://docs.arc.network/app-kit/references/bridge-error-recovery#retry-a-failed-bridge-transfer) * [Retry after a failed mint step](https://docs.arc.network/app-kit/references/bridge-error-recovery#retry-after-a-failed-mint-step) * [Common issues](https://docs.arc.network/app-kit/references/bridge-error-recovery#common-issues) * [Insufficient balance](https://docs.arc.network/app-kit/references/bridge-error-recovery#insufficient-balance) * [Transaction stuck or failed](https://docs.arc.network/app-kit/references/bridge-error-recovery#transaction-stuck-or-failed) * [Best practices](https://docs.arc.network/app-kit/references/bridge-error-recovery#best-practices) Bridge transfers can encounter two error types. Hard errors stop execution. Soft errors let you recover and retry the bridge transfer. App Kit provides error handling that helps you respond in both cases. Hard errors throw exceptions such as validation errors, configuration issues, and authentication problems. Soft errors occur during the bridge transfer but return enough transaction information for recovery. Examples include insufficient balance, network timeouts, and RPC connectivity issues. This guide helps you identify failure points, recover partial bridge transfers, and implement error handling patterns. [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#bridge-transfer-failures) Bridge transfer failures --------------------------------------------------------------------------------------------------------------------------- This section explains how to identify where a bridge transfer failed and resume the bridge transfer manually. ### [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#transaction-steps-overview) Transaction steps overview Each bridge transfer uses Circle’s CCTP protocol provider, which breaks each transaction into various steps: * `approve`: Allows the contract to spend USDC. * `burn`: Burns USDC on the source blockchain and generates an attestation. * `fetchAttestation`: Waits for Circle to sign the burn proof. * `mint`: Mints USDC on the destination blockchain with the attestation. ### [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#bridge-result-details) Bridge result details When a bridge transfer fails, App Kit returns a `BridgeResult` object showing which steps completed and which failed. This lets you resume the bridge transfer manually using the `CCTPv2BridgingProvider`, as shown in examples for [failed attestation fetch](https://docs.arc.network/app-kit/references/bridge-error-recovery#failed-attestation-fetch) and [failed mint](https://docs.arc.network/app-kit/references/bridge-error-recovery#failed-mint) . Focus on these `BridgeResult` properties during recovery: * `result.state` - shows whether the bridge transfer succeeded or failed (`pending`, `success`, `error`) * `result.steps` - each object contains: * `name`: the name of the step * `state`: the status of the step * `txHash`: the transaction hash if the step completed * `error`: an error message if the step failed This example shows a returned `result` object for a transaction that failed when fetching an attestation: Shell result.state: 'error' result.steps: [\ { name: 'approve', state: 'success', txHash: '0x123...' },\ { name: 'burn', state: 'success', txHash: '0x456...' },\ { name: 'fetchAttestation', state: 'error', error: 'Network timeout' },\ ] **Note**: The `result.source` and `result.destination` from [`BridgeResult`](https://docs.arc.network/app-kit/references/sdk-reference#bridgeresult) only contain address and blockchain properties. To use provider methods for recovery, you need to reconstruct full wallet contexts with adapter and chain properties. ### [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#step-analysis) Step analysis This example shows how to check for completed steps and use a helper function to find specific steps: TypeScript // Start a bridge transfer that might fail const result = await kit.bridge({ from: { adapter: sourceAdapter, chain: "Ethereum_Sepolia" }, to: { adapter: destAdapter, chain: "Arc_Testnet" }, amount: "1.00", }); // Check which steps completed successfully console.log("Bridge transfer state:", result.state); console.log("Steps:", result.steps); // Helper function to find specific steps const getStep = (stepName: string) => result.steps.find((step) => step.name === stepName); const approveStep = getStep("approve"); const burnStep = getStep("burn"); const attestationStep = getStep("fetchAttestation"); const mintStep = getStep("mint"); [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#recovery-scenarios) Recovery scenarios --------------------------------------------------------------------------------------------------------------- This section describes how you can implement recovery patterns. ### [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#retry-a-failed-bridge-transfer) Retry a failed bridge transfer If a bridge transfer fails, you can retry it with the `retry` method. Pass the failed `BridgeResult` and the `to` and `from` adapters. This example shows how the retry method works: TypeScript const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter, chain: "Arc_Testnet" }, amount: "1.00", }); if (result.state === "error") { const retryResult = await kit.retry(result, { from: adapter, to: adapter, }); console.log(inspect(retryResult, false, null, true)); } else { console.log(inspect(result, false, null, true)); } ### [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#retry-after-a-failed-mint-step) Retry after a failed mint step This example forces the mint step to fail and then retries with a valid `to` adapter: TypeScript import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { AppKit } from "@circle-fin/app-kit"; import type { BridgeResult } from "@circle-fin/app-kit"; import { inspect } from "node:util"; const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); // This is a fake adapter to force an error at the mint step const fakeAdapter = createViemAdapterFromPrivateKey({ privateKey: ("0x" + "1".repeat(64)) as string, }); const findErrorStep = (result: BridgeResult) => { if (result.state === "error") { return result.steps.find((step) => step.state === "error"); } return null; }; const kit = new AppKit(); const result = await kit.bridge({ from: { adapter, chain: "Ethereum_Sepolia" }, to: { adapter: fakeAdapter, chain: "Arc_Testnet" }, amount: "1.00", }); console.log("INITIAL RESULT", inspect(result, false, null, true)); if (result.state === "error") { const errorStep = findErrorStep(result); if ( errorStep && errorStep.errorMessage?.includes("gas required exceeds allowance") // This is an example error message ) { const retryResult = await kit.retry(result, { from: adapter, to: adapter, // To succeed this time we're using the correct adapter }); console.log("RETRY RESULT", inspect(retryResult, false, null, true)); } } [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#common-issues) Common issues ----------------------------------------------------------------------------------------------------- This section lists common issues and solutions. ### [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#insufficient-balance) Insufficient balance Ensure you have enough USDC in your wallet before a bridge transfer to avoid an insufficient balance error. This example checks your wallet balance: TypeScript import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { formatUnits } from "viem"; const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); const balanceAction = await adapter.prepareAction( "usdc.balanceOf", {}, { chain: "Arc_Testnet" }, ); const balance = await balanceAction.execute(); console.log(`USDC balance: ${formatUnits(BigInt(balance), 6)}`); ### [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#transaction-stuck-or-failed) Transaction stuck or failed If a transaction is stuck or failed, check the transaction on a block explorer with the returned `txHash`. For Solana bridge transfers, use Solana Explorer or SolScan. If the transaction failed during the bridge transfer, check the returned `result.steps` to see which [transaction steps](https://docs.arc.network/app-kit/references/bridge-error-recovery#transaction-steps-overview) completed. [​](https://docs.arc.network/app-kit/references/bridge-error-recovery#best-practices) Best practices ------------------------------------------------------------------------------------------------------- Follow these practices for prevention, recovery, and monitoring to improve reliability. **Prevention** * Test your integration on testnets before deploying on mainnet. * Monitor gas prices and adjust during network congestion. * Use dedicated RPC providers such as Alchemy or QuickNode. * Implement multiple RPC fallbacks. * Wrap all bridge transfers in try-catch including adapter setup and bridge calls. **Recovery** * Always save the bridge transfer state for recovery scenarios. * Verify which steps completed before attempting recovery. * Use appropriate timeouts and give network operations enough time to complete. * Implement exponential backoff and use increasing delays for retry logic. **Monitoring and debugging** * Use block explorers to verify transaction status. * Save intermediate results and persist bridge transfer state for recovery scenarios. Was this page helpful? YesNo [How bridge fees work](https://docs.arc.network/app-kit/concepts/bridge-fees) [Swap overview](https://docs.arc.network/app-kit/swap) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Quickstart: Bridge with Circle Wallets - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Quickstart: Bridge with Circle Wallets [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#prerequisites) * [Step 1. Set up the project](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#step-1-set-up-the-project) * [1.1. Set up your development environment](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#1-1-set-up-your-development-environment) * [1.2. Configure TypeScript (optional)](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#1-2-configure-typescript-optional) * [1.3. Configure environment variables](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#1-3-configure-environment-variables) * [Step 2. Bridge USDC](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#step-2-bridge-usdc) * [2.1. Create the script](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#2-1-create-the-script) * [2.2. Run the script](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#2-2-run-the-script) * [2.3. Verify the transaction](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#2-3-verify-the-transaction) This quickstart helps you write a server-side script that bridges USDC between blockchains using the Circle Wallets adapter. The examples in this quickstart use Solana Devnet and Arc Testnet, but you can use any blockchain the Circle Wallets adapter [supports](https://docs.arc.network/app-kit/references/supported-blockchains) as the source or destination. [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#prerequisites) Prerequisites ----------------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * Installed [Node.js v22+](https://nodejs.org/) . * Obtained a [Circle API Key](https://developers.circle.com/w3s/circle-developer-account#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 Solana Devnet and Arc Testnet using the Circle Console. * Funded your wallets with testnet tokens: * Get testnet USDC from the [Circle Faucet](https://faucet.circle.com/) . * Get test native tokens from the [Console Faucet](https://console.circle.com/faucet) . [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#step-1-set-up-the-project) Step 1. Set up the project ------------------------------------------------------------------------------------------------------------------------------------ This step shows you how to prepare your project and environment. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#1-1-set-up-your-development-environment) 1.1. Set up your development environment Create a new directory and install App Kit with the Circle Wallets adapter and supporting tools: Shell # Set up your directory and initialize the project mkdir app-kit-quickstart-bridge-circle-wallets-adapter cd app-kit-quickstart-bridge-circle-wallets-adapter npm init -y # Install App Kit, Circle Wallets adapter, and tools npm install @circle-fin/app-kit @circle-fin/adapter-circle-wallets typescript tsx Only need to bridge and want a lighter install than the full App Kit? Install the standalone bridge package instead: `@circle-fin/bridge-kit` ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell npx tsc --init Then, update the `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#1-3-configure-environment-variables) 1.3. Configure environment variables Create an `.env` file in the project directory: Shell touch .env Then, add your credentials. Replace `YOUR_API_KEY` with your actual Circle Developer API key, `YOUR_ENTITY_SECRET` with your entity secret (64 lowercase alphanumeric characters), and `YOUR_EVM_WALLET_ADDRESS` and `YOUR_SOLANA_WALLET_ADDRESS` with the wallet addresses you control through Circle Wallets. You can fetch the addresses 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: .env CIRCLE_API_KEY=YOUR_API_KEY CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET EVM_WALLET_ADDRESS=YOUR_EVM_WALLET_ADDRESS SOLANA_WALLET_ADDRESS=YOUR_SOLANA_WALLET_ADDRESS Edit `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#step-2-bridge-usdc) Step 2. Bridge USDC ---------------------------------------------------------------------------------------------------------------------- This step shows you how to set up your script, execute the bridge transfer, and check the result. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#2-1-create-the-script) 2.1. Create the script Create an `index.ts` file in the project directory and add the following code. This code sets up your script and bridges 1.00 USDC from Solana Devnet to Arc Testnet. Using a different blockchain as the source or destination? Change the `chain` values in `kit.bridge()` and ensure your source wallet has USDC and both wallets have native tokens. TypeScript // Import App Kit and the Circle Wallets adapter import { AppKit } from "@circle-fin/app-kit"; import { createCircleWalletsAdapter } from "@circle-fin/adapter-circle-wallets"; import { inspect } from "util"; // Initialize the SDK const kit = new AppKit(); const bridgeUSDC = async (): Promise => { try { // Set up the Circle Wallets adapter instance, works for both ecosystems const adapter = createCircleWalletsAdapter({ apiKey: process.env.CIRCLE_API_KEY!, entitySecret: process.env.CIRCLE_ENTITY_SECRET!, }); console.log("---------------Starting Bridging---------------"); // Use the same adapter for the source and destination blockchains const result = await kit.bridge({ from: { adapter, chain: "Solana_Devnet", address: process.env.SOLANA_WALLET_ADDRESS!, // Solana address (developer-controlled) }, to: { adapter, // Use the same adapter instance chain: "Arc_Testnet", address: process.env.EVM_WALLET_ADDRESS!, // EVM address (developer-controlled) }, amount: "1.00", }); console.log("RESULT", inspect(result, false, null, true)); } catch (err) { console.log("ERROR", inspect(err, false, null, true)); } }; void bridgeUSDC(); You can customize your bridges to [collect a fee](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee) , [use the CCTP Forwarding Service](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service) , or [estimate gas and provider fees](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs) before bridging. Proceed only if the cost works for you. ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#2-2-run-the-script) 2.2. Run the script Save the `index.ts` file and run the script in your terminal: npx tsx --env-file=.env index.ts ### [​](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets#2-3-verify-the-transaction) 2.3. Verify the transaction After the script finishes, find the returned `steps` array in the terminal output. Each transaction step includes an `explorerUrl`. Use that link to verify that the USDC amount matches the amount you bridged. The following code is an example of how an `approve` step might look in the terminal output. The values are used in this example only and are not a real transaction: Shell steps: [\ {\ name: "approve",\ state: "success",\ txHash: "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ data: {\ txHash:\ "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ status: "success",\ cumulativeGasUsed: 17138643n,\ gasUsed: 38617n,\ blockNumber: 8778959n,\ blockHash:\ "0xbeadfacefeed1234567890abcdef1234567890abcdef1234567890abcdef12",\ transactionIndex: 173,\ effectiveGasPrice: 1037232n,\ explorerUrl:\ "https://testnet.arcscan.app/tx/0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",\ },\ },\ ]; Was this page helpful? YesNo [Bridge between Solana and EVM](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm) [Collect custom bridge fees](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Quickstart: Swap tokens across chains - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Combine Quickstart: Swap tokens across chains [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#prerequisites) * [Step 1. Set up the project](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#step-1-set-up-the-project) * [1.1. Set up your development environment](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#1-1-set-up-your-development-environment) * [1.2. Configure TypeScript (optional)](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#1-2-configure-typescript-optional) * [1.3. Configure environment variables](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#1-3-configure-environment-variables) * [Step 2. Swap and bridge tokens](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#step-2-swap-and-bridge-tokens) * [2.1. Create the script](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#2-1-create-the-script) * [2.2. Run the script](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#2-2-run-the-script) * [2.3. Verify the transactions](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#2-3-verify-the-transactions) This quickstart walks you through how to use App Kit to swap tokens across blockchains. The examples show how to swap 1.00 EURC for USDC on Arc Testnet and then bridge that USDC to Ethereum Sepolia, but you can use other [supported tokens or blockchains](https://docs.arc.network/app-kit/references/supported-blockchains) . [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#prerequisites) 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 [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) and [Ethereum Sepolia](https://chainlist.org/chain/11155111) . * Funded your EVM wallet with testnet tokens: * EURC on Arc Testnet (for the swap into USDC) * Native tokens on Arc Testnet and Ethereum Sepolia for fees * Obtained a (free) kit key from [Circle Console](https://console.circle.com/) . [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#step-1-set-up-the-project) Step 1. Set up the project -------------------------------------------------------------------------------------------------------------------------------- This step shows you how to prepare your project and environment. ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#1-1-set-up-your-development-environment) 1.1. Set up your development environment Create a new directory and install App Kit and its dependencies: Shell # Set up your directory and initialize a Node.js project mkdir app-kit-quickstart-swap-crosschain cd app-kit-quickstart-swap-crosschain npm init -y # Install App Kit and tools npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem typescript tsx ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell npx tsc --init Then, update the `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#1-3-configure-environment-variables) 1.3. Configure environment variables Create an `.env` file in the project directory: Shell touch .env Then, add your credentials. Replace `YOUR_PRIVATE_KEY` with the private key for your wallet and `YOUR_KIT_KEY` with the kit key from the Circle Console: .env PRIVATE_KEY=YOUR_PRIVATE_KEY KIT_KEY=YOUR_KIT_KEY Edit `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#step-2-swap-and-bridge-tokens) Step 2. Swap and bridge tokens ---------------------------------------------------------------------------------------------------------------------------------------- This step shows you how to set up your script, swap EURC for USDC on Arc Testnet, bridge USDC to Ethereum Sepolia, and check the result. ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#2-1-create-the-script) 2.1. Create the script Create an `index.ts` file in the project directory and add the following code. This code swaps EURC for USDC on Arc Testnet, then bridges that USDC to Ethereum Sepolia: Using other [tokens](https://docs.arc.network/app-kit/references/supported-blockchains#supported-tokens) or [chains](https://docs.arc.network/app-kit/references/supported-blockchains) ? Change the `chain` values in `kit.swap()` and `kit.bridge()`, and the `tokenIn` and `tokenOut` values in `kit.swap()`. The source chain must support Swap and both chains must support Bridge. Bridge transfers USDC only. TypeScript import { AppKit } from "@circle-fin/app-kit"; import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { inspect } from "util"; const kit = new AppKit(); const swapAndBridge = async (): Promise => { try { const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); console.log( "---------------Step 1: Swapping EURC for USDC on Arc Testnet---------------", ); const swapResult = await kit.swap({ from: { adapter, chain: "Arc_Testnet" }, tokenIn: "EURC", tokenOut: "USDC", amountIn: "1.00", config: { kitKey: process.env.KIT_KEY as string, }, }); console.log("Swap result:", inspect(swapResult, false, null, true)); console.log( "---------------Step 2: Bridging USDC to Ethereum Sepolia---------------", ); const bridgeResult = await kit.bridge({ from: { adapter, chain: "Arc_Testnet" }, to: { adapter, chain: "Ethereum_Sepolia" }, amount: swapResult.amountOut, }); console.log("Bridge result:", inspect(bridgeResult, false, null, true)); } catch (err) { console.log("ERROR", inspect(err, false, null, true)); } }; void swapAndBridge(); Customize your flow to [set slippage for the swap](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit) , [collect bridge fees](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee) , or [estimate costs before bridging](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs) . ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#2-2-run-the-script) 2.2. Run the script Save the `index.ts` file and run the script in your terminal: Shell npx tsx --env-file=.env index.ts ### [​](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain#2-3-verify-the-transactions) 2.3. Verify the transactions After the script finishes, find the returned results in the terminal output: * For the swap step, use the `explorerUrl` to verify the swap transaction on Arc Testnet. * For the bridge step, use the `steps` array and each step’s `explorerUrl` to verify the USDC bridge transfer on Arc Testnet and Ethereum Sepolia. The following is an example of how the results might look in the terminal output. The values used are not real transactions. Swap result Bridge result { tokenIn: 'EURC', tokenOut: 'USDC', chain: { chain: 'Arc_Testnet', chainId: 5042002 }, amountIn: '1.00', amountOut: '0.99', txHash: '0x78abb6a896e6b166925cae122b6ab2a6abd49ba23cbbd4749c99d5cccf205897', explorerUrl: 'https://testnet.arcscan.app/tx/0x78abb6a896e6b166925cae122b6ab2a6abd49ba23cbbd4749c99d5cccf205897', fees: [ { token: 'EURC', amount: '0.001', type: 'provider' } ] } Was this page helpful? YesNo [How swap fees work](https://docs.arc.network/app-kit/concepts/swap-fees) [SDK reference](https://docs.arc.network/app-kit/references/sdk-reference) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Adapter setups - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/adapter-setups#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Get started Adapter setups [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) App Kit works with common adapter libraries to integrate smoothly with your existing workflow: * [`viem`](https://viem.sh/) v2 for EVM-compatible blockchains * [`ethers`](https://ethers.org/) v6 for EVM-compatible blockchains * [`solana`](https://solana.com/) for the Solana blockchain * [`circle-wallets`](https://developers.circle.com/wallets/dev-controlled) for your existing Circle Wallets account Pick your adapter to see its setup options. * Viem * Ethers * Solana * Circle Wallets [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#standard-setup) Standard setup ----------------------------------------------------------------------------------------------- The standard setup is the fastest way to start. Create one adapter from your wallet private key that works across multiple blockchains.This setup uses public RPC endpoints and factory functions. For production, you should configure a [custom RPC](https://docs.arc.network/app-kit/tutorials/adapter-setups#custom-rpc) . Public connections have rate limits and might be slow. TypeScript import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#custom-rpc) Custom RPC --------------------------------------------------------------------------------------- You can replace the public RPC from the [standard setup](https://docs.arc.network/app-kit/tutorials/adapter-setups#standard-setup) with your own connection. For production, you should use a paid service like [Alchemy](https://www.alchemy.com/) or [QuickNode](https://www.quicknode.com/) . These services are more reliable than free connections.To use your own connection, replace the default one and add your custom RPC endpoints. Map each chain to its RPC endpoint so one adapter can work across multiple chains. This example uses Alchemy connections: TypeScript import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { EthereumSepolia, ArcTestnet } from "@circle-fin/app-kit/chains"; import { createPublicClient, http } from "viem"; // Map RPC endpoints by chain name const RPC_BY_CHAIN_NAME: Record = { [EthereumSepolia.name]: `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, [ArcTestnet.name]: `https://arc-testnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, }; // Create an adapter const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, // Replace the default connection getPublicClient: ({ chain }) => { const rpcUrl = RPC_BY_CHAIN_NAME[chain.name]; if (!rpcUrl) { throw new Error(`No RPC configured for chain: ${chain.name}`); } return createPublicClient({ chain, transport: http(rpcUrl, { retryCount: 3, timeout: 10000, }), }); }, }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#browser-wallet) Browser wallet ----------------------------------------------------------------------------------------------- You can create an adapter from browser wallet apps like [MetaMask](https://metamask.io/) or [Phantom](https://phantom.com/) : TypeScript import { createViemAdapterFromProvider } from "@circle-fin/adapter-viem-v2"; import type { EIP1193Provider } from "viem"; declare global { interface Window { ethereum?: EIP1193Provider; } } // Check if wallet provider is available if (!window.ethereum) { throw new Error("No wallet provider found"); } const adapter = await createViemAdapterFromProvider({ provider: window.ethereum, }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#standard-setup-2) Standard setup ------------------------------------------------------------------------------------------------- The standard setup is the fastest way to start. Create one adapter from your wallet private key that works across multiple blockchains.This setup uses public RPC endpoints and factory functions. For production, you should configure a [custom RPC](https://docs.arc.network/app-kit/tutorials/adapter-setups#custom-rpc) . Public connections have rate limits and might be slow. TypeScript import { createEthersAdapterFromPrivateKey } from "@circle-fin/adapter-ethers-v6"; const adapter = createEthersAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#custom-rpc-2) Custom RPC ----------------------------------------------------------------------------------------- You can replace the public RPC from the [standard setup](https://docs.arc.network/app-kit/tutorials/adapter-setups#standard-setup) with your own connection. For production, you should use a paid service like [Alchemy](https://www.alchemy.com/) or [QuickNode](https://www.quicknode.com/) . These services are more reliable than free connections.To use your own connection, replace the default one and add your custom RPC endpoints. Map each chain to its RPC endpoint so one adapter can work across multiple chains. This example uses Alchemy connections: TypeScript import { createEthersAdapterFromPrivateKey } from "@circle-fin/adapter-ethers-v6"; import { EthereumSepolia, ArcTestnet } from "@circle-fin/app-kit/chains"; import { JsonRpcProvider } from "ethers"; // Map RPC endpoints by chain name const RPC_BY_CHAIN_NAME: Record = { [EthereumSepolia.name]: `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, [ArcTestnet.name]: `https://arc-testnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, }; // Create an adapter const adapter = createEthersAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, // Replace the default connection getProvider: ({ chain }) => { const rpcUrl = RPC_BY_CHAIN_NAME[chain.name]; if (!rpcUrl) { throw new Error(`No RPC configured for chain: ${chain.name}`); } return new JsonRpcProvider(rpcUrl); }, }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#browser-wallet-2) Browser wallet ------------------------------------------------------------------------------------------------- You can create an adapter from browser wallet apps like [MetaMask](https://metamask.io/) or [Phantom](https://phantom.com/) : TypeScript import { createEthersAdapterFromProvider } from "@circle-fin/adapter-ethers-v6"; import type { Eip1193Provider } from "ethers"; declare global { interface Window { ethereum?: Eip1193Provider; } } // Check if wallet is installed if (!window.ethereum) { throw new Error("No wallet provider found"); } const adapter = await createEthersAdapterFromProvider({ provider: window.ethereum, }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#standard-setup-3) Standard setup ------------------------------------------------------------------------------------------------- The standard setup is the fastest way to start. Create one adapter from your wallet private key that works across multiple blockchains.This setup uses public RPC endpoints and factory functions. For production, you should configure a [custom RPC](https://docs.arc.network/app-kit/tutorials/adapter-setups#custom-rpc) . Public connections have rate limits and might be slow. TypeScript import { createSolanaKitAdapterFromPrivateKey } from "@circle-fin/adapter-solana-kit"; // Solana accepts Base58, Base64, or JSON array format private keys const adapter = createSolanaKitAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#custom-rpc-3) Custom RPC ----------------------------------------------------------------------------------------- You can replace the public RPC from the [standard setup](https://docs.arc.network/app-kit/tutorials/adapter-setups#standard-setup) with your own connection. For production, you should use a paid service like [Alchemy](https://www.alchemy.com/) or [QuickNode](https://www.quicknode.com/) . These services are more reliable than free connections.To use your own connection, create a custom connection to your RPC endpoint. Point to that connection when making a Solana adapter. This example creates a custom connection using Alchemy: TypeScript import { createSolanaKitAdapterFromPrivateKey } from "@circle-fin/adapter-solana-kit"; import { createSolanaRpc } from "@solana/kit"; // Create an adapter const adapter = createSolanaKitAdapterFromPrivateKey({ privateKey: process.env.SOLANA_PRIVATE_KEY as string, // Replace the default connection getRpc: () => // Use an Alchemy connection createSolanaRpc( `https://solana-devnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, ), }); [​](https://docs.arc.network/app-kit/tutorials/adapter-setups#browser-wallet-3) Browser wallet ------------------------------------------------------------------------------------------------- You can create an adapter from browser wallet apps like [MetaMask](https://metamask.io/) or [Phantom](https://phantom.com/) : TypeScript import { createSolanaKitAdapterFromProvider, SolanaKitWalletProvider, } from "@circle-fin/adapter-solana-kit"; declare global { interface Window { solana?: SolanaKitWalletProvider; } } if (window.solana) { const adapter = await createSolanaKitAdapterFromProvider({ provider: window.solana, }); } server-side onlyYou can use the Circle Wallets adapter if you already [manage wallets through Circle](https://developers.circle.com/wallets) . Suited for enterprise and backend applications, it uses developer-controlled wallets and Circle Contracts so you can use App Kit on [supported blockchains](https://docs.arc.network/app-kit/references/supported-blockchains#adapters) without managing private keys yourself.The Circle Wallets adapter requires these credentials from the [Circle Console](https://console.circle.com/) : * **[API Key](https://developers.circle.com/w3s/circle-developer-account#creating-an-api-key-for-developer-services) :** Environment-prefixed (examples: `TEST_API_KEY:abc123:def456`, `LIVE_API_KEY:xyz:uvw`) or Base64-encoded * **[Entity Secret](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) :** 64 lowercase alphanumeric characters This code block initializes the Circle Wallets adapter: Typescript import { createCircleWalletsAdapter } from "@circle-fin/adapter-circle-wallets"; // Initialize adapter with Circle credentials (server-side only) const adapter = createCircleWalletsAdapter({ apiKey: process.env.CIRCLE_API_KEY!, // Format: TEST_API_KEY:abc:def or Base64 entitySecret: process.env.CIRCLE_ENTITY_SECRET!, // Format: 64 lowercase alphanumeric chars }); The Circle Wallets adapter does not support [gas sponsorship](https://developers.circle.com/wallets/gas-station) for crosschain transfers that originate on Solana. For those transactions, the user’s Solana wallet must hold sufficient SOL to pay network fees. Was this page helpful? YesNo [Supported blockchains and tokens](https://docs.arc.network/app-kit/references/supported-blockchains) [Send overview](https://docs.arc.network/app-kit/send) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # How-to: Set slippage tolerance or stop limit on swaps - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Customize swapping How-to: Set slippage tolerance or stop limit on swaps [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit#prerequisites) * [Set slippage tolerance](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit#set-slippage-tolerance) * [Set stop limit](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit#set-stop-limit) Set a slippage tolerance or stop limit to avoid receiving less than expected on a swap due to market fluctuations: * A **slippage tolerance** lets you set the maximum percentage difference you’re willing to accept between the estimated and actual swap amount, expressed in bps (for example, 100 bps = 1%). * A **stop limit** lets you set the exact minimum amount you want to receive. If both are configured, the stop limit takes precedence. [​](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------------------------------ Before you begin, ensure that you’ve: * [Installed App Kit](https://docs.arc.network/app-kit/tutorials/installation) * [Configured an adapter](https://docs.arc.network/app-kit/tutorials/adapter-setups) These are required so any example below runs with a valid `kit` and `adapter`. [​](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit#set-slippage-tolerance) Set slippage tolerance ------------------------------------------------------------------------------------------------------------------------------------------ This example sets a slippage tolerance of 100 bps (1%): TypeScript const output = await kit.swap({ from: { adapter, chain: "Arc_Testnet" }, tokenIn: "USDC", amountIn: "1.00", tokenOut: "EURC", config: { // Set the slippage tolerance to 100 bps slippageBps: 100, }, }); With `slippageBps` as `100` as in the example, you’ll receive at least 99% of the estimated amount. Meaning if the swap rate is 1 USDC to 1 EURC, you’ll receive at least 0.99 EURC. The `slippageBps` default is 300 bps. `0` represents no tolerance, which increases transaction failure rates. [​](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit#set-stop-limit) Set stop limit -------------------------------------------------------------------------------------------------------------------------- `stopLimit` defines the minimum amount of the token type specified in `tokenOut` that you’ll receive on a swap. This example sets a stop limit of 0.95 EURC, meaning you won’t receive any less than that on a swap: TypeScript const output = await kit.swap({ from: { adapter, chain: "Arc_Testnet" }, tokenIn: "USDC", amountIn: "1.00", tokenOut: "EURC", config: { // Set stop limit to 0.95 EURC stopLimit: "0.95", }, }); Was this page helpful? YesNo [Estimate swap rate](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate) [How swap fees work](https://docs.arc.network/app-kit/concepts/swap-fees) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # App Kit SDK reference - Arc Docs [Skip to main content](https://docs.arc.network/app-kit/references/sdk-reference#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation App Kit App Kit SDK reference [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [AppKit Class](https://docs.arc.network/app-kit/references/sdk-reference#appkit-class) * [constructor(config?)](https://docs.arc.network/app-kit/references/sdk-reference#constructor-config) * [AppKitConfig](https://docs.arc.network/app-kit/references/sdk-reference#appkitconfig) * [Methods](https://docs.arc.network/app-kit/references/sdk-reference#methods) * [bridge(params)](https://docs.arc.network/app-kit/references/sdk-reference#bridge-params) * [estimateBridge(params)](https://docs.arc.network/app-kit/references/sdk-reference#estimatebridge-params) * [estimateSend(params)](https://docs.arc.network/app-kit/references/sdk-reference#estimatesend-params) * [estimateSwap(params)](https://docs.arc.network/app-kit/references/sdk-reference#estimateswap-params) * [getSupportedChains(operationType)](https://docs.arc.network/app-kit/references/sdk-reference#getsupportedchains-operationtype) * [off(action)](https://docs.arc.network/app-kit/references/sdk-reference#off-action) * [on(action)](https://docs.arc.network/app-kit/references/sdk-reference#on-action) * [send(params)](https://docs.arc.network/app-kit/references/sdk-reference#send-params) * [swap(params)](https://docs.arc.network/app-kit/references/sdk-reference#swap-params) * [Method Parameters](https://docs.arc.network/app-kit/references/sdk-reference#method-parameters) * [BridgeParams](https://docs.arc.network/app-kit/references/sdk-reference#bridgeparams) * [BridgeConfig](https://docs.arc.network/app-kit/references/sdk-reference#bridgeconfig) * [AdapterContext](https://docs.arc.network/app-kit/references/sdk-reference#adaptercontext) * [CCTPConfig](https://docs.arc.network/app-kit/references/sdk-reference#cctpconfig) * [VersionConfig](https://docs.arc.network/app-kit/references/sdk-reference#versionconfig) * [SendParams](https://docs.arc.network/app-kit/references/sdk-reference#sendparams) * [SwapParams](https://docs.arc.network/app-kit/references/sdk-reference#swapparams) * [SwapConfig](https://docs.arc.network/app-kit/references/sdk-reference#swapconfig) * [CCTPSplitConfig](https://docs.arc.network/app-kit/references/sdk-reference#cctpsplitconfig) * [CCTPMergedConfig](https://docs.arc.network/app-kit/references/sdk-reference#cctpmergedconfig) * [Method Results](https://docs.arc.network/app-kit/references/sdk-reference#method-results) * [BridgeResult](https://docs.arc.network/app-kit/references/sdk-reference#bridgeresult) * [BridgeStep](https://docs.arc.network/app-kit/references/sdk-reference#bridgestep) * [EstimateResult](https://docs.arc.network/app-kit/references/sdk-reference#estimateresult) * [EstimatedGas](https://docs.arc.network/app-kit/references/sdk-reference#estimatedgas) * [SwapEstimate](https://docs.arc.network/app-kit/references/sdk-reference#swapestimate) * [SwapResult](https://docs.arc.network/app-kit/references/sdk-reference#swapresult) * [Supporting Types](https://docs.arc.network/app-kit/references/sdk-reference#supporting-types) * [TransferSpeed](https://docs.arc.network/app-kit/references/sdk-reference#transferspeed) * [ChainDefinition](https://docs.arc.network/app-kit/references/sdk-reference#chaindefinition) * [EVMChainDefinition](https://docs.arc.network/app-kit/references/sdk-reference#evmchaindefinition) * [Blockchain](https://docs.arc.network/app-kit/references/sdk-reference#blockchain) * [KitContractType](https://docs.arc.network/app-kit/references/sdk-reference#kitcontracttype) * [Currency](https://docs.arc.network/app-kit/references/sdk-reference#currency) * [NonEVMChainDefinition](https://docs.arc.network/app-kit/references/sdk-reference#nonevmchaindefinition) * [AllowanceStrategy](https://docs.arc.network/app-kit/references/sdk-reference#allowancestrategy) * [OperationType](https://docs.arc.network/app-kit/references/sdk-reference#operationtype) * [DeveloperFeeHooks](https://docs.arc.network/app-kit/references/sdk-reference#developerfeehooks) * [BaseChainDefinition](https://docs.arc.network/app-kit/references/sdk-reference#basechaindefinition) * [TokenInfo](https://docs.arc.network/app-kit/references/sdk-reference#tokeninfo) * [Event Types](https://docs.arc.network/app-kit/references/sdk-reference#event-types) * [Bridge Events](https://docs.arc.network/app-kit/references/sdk-reference#bridge-events) This reference guide describes the public interfaces, methods, and types available in the App Kit SDK. [​](https://docs.arc.network/app-kit/references/sdk-reference#appkit-class) AppKit Class ------------------------------------------------------------------------------------------- The `AppKit` is how you’ll perform all stablecoin operations including crosschain bridging, same-chain swaps, token transfers, and fee estimation. It also enables you to add event listeners for bridge transfers. ### [​](https://docs.arc.network/app-kit/references/sdk-reference#constructor-config) constructor(config?) Creates a new `AppKit` instance. constructor(config?: AppKitConfig) **Parameters** | Name | Type | Description | | --- | --- | --- | | config | [`AppKitConfig`](https://docs.arc.network/app-kit/references/sdk-reference#appkitconfig) | Optional context overrides used for fee estimation utilities | **Usage** import { AppKit } from "@circle-fin/app-kit"; const kit = new AppKit(); ### [​](https://docs.arc.network/app-kit/references/sdk-reference#appkitconfig) AppKitConfig type AppKitConfig = CreateContextParams & { developerFee?: Partial; }; * * * * * * [​](https://docs.arc.network/app-kit/references/sdk-reference#methods) Methods --------------------------------------------------------------------------------- ### [​](https://docs.arc.network/app-kit/references/sdk-reference#bridge-params) bridge(params) Execute a crosschain USDC bridge transfer. Transfers USDC between different blockchain networks using Circle’s Cross-Chain Transfer Protocol (CCTP). Supports both fast and standard transfer speeds with automatic attestation handling. async bridge(params: BridgeParams): BridgeResult **Parameters** | Name | Type | Description | | --- | --- | --- | | params | [`BridgeParams`](https://docs.arc.network/app-kit/references/sdk-reference#bridgeparams) | Bridge parameters containing source, destination, amount, and token | **Returns** [BridgeResult](https://docs.arc.network/app-kit/references/sdk-reference#bridgeresult) **Usage Example** const result = await kit.bridge({ from: sourceAdapter, to: { adapter: destAdapter, chain: "Polygon" }, amount: "100.50", token: "USDC", }); console.log("Bridge completed:", result.hash); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#estimatebridge-params) estimateBridge(params) Estimate the bridge operation. Calculates gas costs, protocol fees, and optional custom fees for a crosschain bridge transfer without executing the transaction. Useful for displaying cost estimates to users before they confirm a transfer. async estimateBridge(params: BridgeParams): EstimateResult **Parameters** | Name | Type | Description | | --- | --- | --- | | params | [`BridgeParams`](https://docs.arc.network/app-kit/references/sdk-reference#bridgeparams) | Bridge parameters containing source, destination, amount, and token | **Returns** [EstimateResult](https://docs.arc.network/app-kit/references/sdk-reference#estimateresult) **Usage Example** const estimate = await kit.estimateBridge({ from: sourceAdapter, to: { adapter: destAdapter, chain: "Polygon" }, amount: "100.50", token: "USDC", }); console.log("Estimated fee:", estimate.fee); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#estimatesend-params) estimateSend(params) Estimate network fees for a send operation. Prepare the send (validation + recipient resolution) and returns the gas estimate without executing the actual transaction. This allows developers to show users the cost before committing to the transfer. async estimateSend(params: SendParams): EstimatedGas **Parameters** | Name | Type | Description | | --- | --- | --- | | params | [`SendParams`](https://docs.arc.network/app-kit/references/sdk-reference#sendparams) | Send parameters: source, destination (address or adapter), amount, token. | **Returns** [EstimatedGas](https://docs.arc.network/app-kit/references/sdk-reference#estimatedgas) **Usage Examples** const estimate = await kit.estimateSend({ from: sourceAdapter, to: { adapter: destAdapter, chain: "Polygon" }, amount: "100.50", token: "USDC", }); console.log("Estimated gas:", estimate.gas); const estimate = await kit.estimateSend({ from: sourceAdapter, to: { adapter: destAdapter, chain: "Polygon" }, amount: "50.0", token: "USDT", }); console.log("Estimated gas:", estimate.gas); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#estimateswap-params) estimateSwap(params) Estimate the output and fees for a swap operation. Calculates the expected output amount, minimum output (with slippage), and fee breakdown for a token swap without executing the transaction. async estimateSwap(params: SwapParams): SwapEstimate **Parameters** | Name | Type | Description | | --- | --- | --- | | params | [`SwapParams`](https://docs.arc.network/app-kit/references/sdk-reference#swapparams) | Swap parameters containing source, tokens, amount, and config | **Returns** [SwapEstimate](https://docs.arc.network/app-kit/references/sdk-reference#swapestimate) **Usage Example** const estimate = await kit.estimateSwap({ from: { adapter, chain: "Ethereum" }, tokenIn: "USDC", tokenOut: "USDT", amountIn: "100.50", config: { slippageBps: 300, kitKey: "KIT_KEY:id:secret", }, }); console.log("Stop limit:", estimate.stopLimit.amount, estimate.stopLimit.token); console.log( "Estimated output:", estimate.estimatedOutput.amount, estimate.estimatedOutput.token, ); console.log("Fees:", estimate.fees); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#getsupportedchains-operationtype) getSupportedChains(operationType) Get chains supported by AppKit operations. Returns blockchain networks that support specific stablecoin operations. When no operation type is specified, returns all chains supporting any operation (bridge or swap). getSupportedChains(operationType: OperationType): ChainDefinition[] **Parameters** | Name | Type | Description | | --- | --- | --- | | operationType | [`OperationType`](https://docs.arc.network/app-kit/references/sdk-reference#operationtype) | Optional operation type to filter chains (`bridge` \| `swap`) | **Returns** ChainDefinition\[\] **Usage Examples** import { AppKit } from "@circle-fin/app-kit"; const kit = new AppKit(); const allChains = kit.getSupportedChains(); console.log(`Total supported chains: ${allChains.length}`); allChains.forEach((chain) => { console.log(`- ${chain.name} (${chain.type})`); }); const kit = new AppKit(); const bridgeChains = kit.getSupportedChains("bridge"); console.log( "Chains supporting bridge:", bridgeChains.map((c) => c.name), ); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#off-action) off(action) Unregister an event handler for a specific AppKit action. This method removes a previously registered event handler. You must pass the exact same handler function reference that was used during registration. Use the wildcard `*` to remove handlers listening to all actions. off(action: K, handler: (payload: any) => void): void **Parameters** | Name | Type | Description | | --- | --- | --- | | action | `K` | The action name (prefixed with `bridge.`) or `*` for all actions | | handler | `(payload: any) => void` | The handler function to remove (must be the same reference) | **Usage Example** import { AppKit } from "@circle-fin/app-kit"; const kit = new AppKit(); // Define handler const handler = (payload) => { console.log("Approval:", payload); }; // Register kit.on("bridge.approve", handler); // Later, unregister kit.off("bridge.approve", handler); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#on-action) on(action) Register an event handler for a specific AppKit action. Subscribe to events emitted during bridge operations. All bridge events are prefixed with `bridge.` (e.g., `bridge.approve`, `bridge.burn`) to namespace them within the AppKit event system. Handlers receive strongly-typed payloads based on the action name. Multiple handlers can be registered for the same action, and all will be invoked when the action occurs. Use the wildcard `*` to listen to all actions. on(action: K, handler: (payload: any) => void): void **Parameters** | Name | Type | Description | | --- | --- | --- | | action | `K` | The action name (prefixed with `bridge.`) or `*` for all actions | | handler | `(payload: any) => void` | Callback function to invoke when the action occurs | **Usage Example** import { AppKit } from "@circle-fin/app-kit"; const kit = new AppKit(); // Listen to specific bridge action kit.on("bridge.approve", (payload) => { console.log("Approval transaction:", payload.values.txHash); }); // Listen to all actions kit.on("*", (payload) => { console.log("Action:", payload.method); }); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#send-params) send(params) Execute a send operation for known token aliases (USDC, USDT, NATIVE) or custom ERC-20/SPL tokens. For custom tokens, the token address must be provided. This method handles the complete send transfer flow using the underlying AppKit infrastructure. It supports sending to either a destination adapter or an explicit recipient address, with full type safety and comprehensive error handling. async send(params: SendParams): BridgeStep **Parameters** | Name | Type | Description | | --- | --- | --- | | params | [`SendParams`](https://docs.arc.network/app-kit/references/sdk-reference#sendparams) | Send parameters containing source, destination, amount, and token | **Returns** [BridgeStep](https://docs.arc.network/app-kit/references/sdk-reference#bridgestep) **Usage Examples** // Send USDC to another adapter const result = await kit.send({ from: sourceAdapter, to: { adapter: destAdapter, chain: "Polygon" }, amount: "100.50", token: "USDC", }); console.log("Send completed:", result.txHash); // Send a custom token to an explicit address const result = await kit.send({ from: sourceAdapter, to: "0x742d35Cc4634C0532925a3b8D1d7", amount: "100.50", token: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI on Ethereum }); console.log("Send completed:", result.txHash); // Send USDT to an explicit address const result = await kit.send({ from: sourceAdapter, to: { address: "0x742d35Cc4634C0532925a3b8D1d7", chain: "Polygon" }, amount: "50.25", token: "USDT", }); console.log("Send completed:", result.txHash); * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#swap-params) swap(params) Execute a same-chain token swap operation. Swaps between USDC, USDT, and native tokens on the same blockchain with configurable slippage tolerance and allowance strategies. async swap(params: SwapParams): SwapResult **Parameters** | Name | Type | Description | | --- | --- | --- | | params | [`SwapParams`](https://docs.arc.network/app-kit/references/sdk-reference#swapparams) | Swap parameters containing source, tokens, amount, and config | **Returns** [SwapResult](https://docs.arc.network/app-kit/references/sdk-reference#swapresult) **Usage Example** const result = await kit.swap({ from: { adapter, chain: "Ethereum" }, tokenIn: "USDC", tokenOut: "USDT", amountIn: "100.50", config: { slippageBps: 300, // 3% slippage allowanceStrategy: "permit", kitKey: "KIT_KEY:id:secret", }, }); console.log("Swap completed:", result.txHash); * * * [​](https://docs.arc.network/app-kit/references/sdk-reference#method-parameters) Method Parameters ----------------------------------------------------------------------------------------------------- ### [​](https://docs.arc.network/app-kit/references/sdk-reference#bridgeparams) BridgeParams Parameters for initiating a crosschain USDC bridge transfer. This type is used as the primary input to BridgeKit.bridge, allowing users to specify the source and destination adapters, transfer amount, and optional configuration. * The `from` field specifies the source adapter context (wallet and chain). * The `to` field specifies the destination, supporting both explicit and derived recipient addresses. * The `config` field allows customization of bridge behavior (e.g., transfer speed). * The `token` field is optional and defaults to `USDC`; other tokens are not currently supported. interface BridgeParams { amount: string; config?: BridgeConfig; from: AdapterContext; invocationMeta?: InvocationMeta; to: BridgeDestination; token?: "USDC"; } **Properties** | Name | Type | Description | | --- | --- | --- | | amount | string | The amount to transfer | | config | BridgeConfig | Optional bridge configuration (e.g., transfer speed). If omitted, defaults will be used | | from | `AdapterContext` | The source adapter context (wallet and chain) for the transfer. | | invocationMeta | InvocationMeta | Optional invocation metadata for tracing and correlation.

When provided, the `traceId` is used to correlate all events emitted during the bridge operation. If not provided, an OpenTelemetry-compatible `traceId` will be auto-generated. | | to | `BridgeDestination` | The destination for the transfer, supporting explicit or derived recipient addresses | | token | `'USDC'` | The token to transfer. Defaults to `USDC`. If omitted, the provider will use `USDC` by default. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#bridgeconfig) BridgeConfig Configuration options for customizing bridge behavior. interface BridgeConfig { customFee?: CustomFee maxFee?: string transferSpeed?: TransferSpeed \| 'FAST' \| 'SLOW' } **Properties** | Name | Type | Description | | --- | --- | --- | | customFee | CustomFee | The custom fee to charge for the transfer.

Whatever value you provide here is added on top of the transfer amount. The user must have enough balance for `amount + customFee`, and the wallet signs for that total on the source chain. The custom fee is split automatically:

\- 10% routes to Circle.
\- 90% routes to your `recipientAddress`.

The original transfer amount proceeds through CCTPv2 unchanged, and the protocol fee (1–14 bps in FAST mode, 0% in STANDARD) is taken from that transfer amount. | | maxFee | string | The maximum fee to pay for the burn operation.

Provide the amount as a base-10 numeric string representing the token amount in human-readable format. For example: to set a maximum fee of 1 USDC, pass `"1"`. Decimal values are supported (e.g., `"0.5"` for half a USDC). | | transferSpeed | `TransferSpeed \| 'FAST' \| 'SLOW'` | The transfer speed mode for CCTPv2 transfers.

Controls whether to use fast burn mode (FAST) or standard mode (SLOW). Fast burn may reduce transfer time but could have different fee implications. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#adaptercontext) AdapterContext Represents the context of an adapter used for crosschain operations. An AdapterContext must always specify both the adapter and the chain explicitly. The address field behavior is determined by the adapter’s address control model: * Developer-controlled adapters: The `address` field is required because each operation must explicitly specify which address to use. * User-controlled adapters: The `address` field is forbidden because the address is automatically resolved from the connected wallet or signer. * Legacy adapters: The `address` field remains optional for backward compatibility. This ensures clear, debuggable code where the intended chain is always visible at the call site, and address requirements are enforced at compile time based on adapter capabilities. type AdapterContext = { adapter: Adapter; chain: TChainIdentifier; } & AddressField>; * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#cctpconfig) CCTPConfig Configuration for the Cross-Chain Transfer Protocol (CCTP). interface CCTPConfig { contracts: Partial; domain: number; forwarderSupported: object; } **Properties** | Name | Type | Description | | --- | --- | --- | | contracts | `Partial` | The contracts required for CCTP. | | domain | number | The CCTP domain identifier. | | forwarderSupported | object | Indicates whether the chain supports forwarder for source and destination. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#versionconfig) VersionConfig Version configuration for CCTP contracts. Defines whether the chain uses split or merged CCTP contract architecture. Split configuration uses separate TokenMessenger and MessageTransmitter contracts, while merged configuration uses a single unified contract. type VersionConfig = CCTPSplitConfig | CCTPMergedConfig; * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#sendparams) SendParams Parameters for sending USDC, USDT, native tokens, or custom ERC-20/SPL tokens. This interface is the canonical input for send operations in App Kit. It supports sending to either a destination AdapterContext (recipient derives from the adapter’s default account) or an explicit recipient `string` address on the destination chain. * The `from` field provides the source signing context and chain. * The `to` field identifies the destination as an adapter context or an explicit address. * The `amount` field is a human-readable decimal string (for example, `10.5`). * The `token` field selects the asset to move and defaults to `USDC`. interface SendParams { amount: string from: AdapterContext to: string \| Adapter token?: TokenAlias \| TokenAddress } **Properties** | Name | Type | Description | | --- | --- | --- | | amount | string | The amount to transfer. | | from | AdapterContext | The source adapter context (wallet and chain) for the transfer. | | to | `string \| Adapter` | The destination for the transfer, supporting explicit or derived recipient addresses. | | token | `TokenAlias \| TokenAddress` | The token to transfer. Defaults to `USDC`. If omitted, the provider will use `USDC` by default.

Supports both known aliases and custom token contract addresses:
\- Known aliases: `USDC`, `USDT`, `NATIVE`
\- Custom token addresses: EVM addresses or Solana SPL token mint addresses | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#swapparams) SwapParams Parameters for initiating a same-chain stablecoin swap. This type is used as the primary input to swap operations, allowing users to specify the source context, input/output tokens, swap amount, and optional configuration. SwapKit supports swaps between stablecoins (USDC, USDT, EURC, USDe, DAI, PYUSD), wrapped tokens (WBTC, WETH, WSOL, WAVAX, WPOL), and native tokens (e.g., ETH on Ethereum, SOL on Solana) via the `NATIVE` alias. * The `from` field specifies the source adapter context (wallet and chain). The chain must be a SwapChain member (or its corresponding string literal) so IDE autocomplete only surfaces swap-supported networks. * The `tokenIn` field specifies the input token (see SupportedToken). * The `tokenOut` field specifies the output token (see SupportedToken). * The `amountIn` field is a human-readable decimal string (e.g., `10.5`). * The `config` field allows customization of swap behavior. interface SwapParams { amountIn: string config?: SwapConfig from: SwapAdapterContext tokenIn: infer tokenOut: infer } **Properties** | Name | Type | Description | | --- | --- | --- | | amountIn | string | The amount of the input token to swap.

Expressed as a human-readable decimal string in token units (e.g., `0.05` for 0.05 USDC or 0.05 ETH). | | config | SwapConfig | Optional configuration for swap behavior.

If omitted, defaults will be used:
\- `allowanceStrategy`: `permit` (fallback to `approve`)
\- `slippageBps`: 300 (3%) | | from | `SwapAdapterContext` | The source adapter context (wallet and chain) for the swap. | | tokenIn | `infer` | The input token to swap from.

Supports stablecoins (USDC, USDT, EURC, USDe, DAI, PYUSD), wrapped tokens (WBTC, WETH, WSOL, WAVAX, WPOL), and native tokens (NATIVE or chain-specific symbols). | | tokenOut | `infer` | The output token to swap to.

Supports stablecoins (USDC, USDT, EURC, USDe, DAI, PYUSD), wrapped tokens (WBTC, WETH, WSOL, WAVAX, WPOL), and native tokens (NATIVE or chain-specific symbols). | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#swapconfig) SwapConfig Configuration options for swap operations. Controls swap behavior including allowance strategy, slippage tolerance, minimum output amounts, custom fees, and kit identification. interface SwapConfig { allowanceStrategy?: AllowanceStrategy; customFee?: object; kitKey?: string; slippageBps?: number; stopLimit?: string; } **Properties** | Name | Type | Description | | --- | --- | --- | | allowanceStrategy | AllowanceStrategy | Strategy for granting token allowances to the swap contract.

Defaults to `permit` with fallback to `approve`. | | customFee | object | Custom fee configuration for this swap (percentage-based approach).

Allows specifying a percentage fee and recipient address at the transaction level. This is mutually exclusive with kit-level callback fee policy. If both are set, transaction-level takes precedence.

For complex fee logic (VIP tiers, database lookups), use kit-level callback approach via `setCustomFeePolicy()` instead. | | kitKey | string | Identifier for the kit instance initiating this swap.

Used for tracking and analytics purposes. | | slippageBps | number | Maximum acceptable slippage in basis points (BPS).

1 BPS = 0.01%, so 300 BPS = 3% slippage. Defaults to 300 BPS (3%). | | stopLimit | string | Minimum acceptable output amount in human-readable format (stop-limit).

If the estimated output falls below this value, the swap will fail. Expressed as a decimal string (e.g., `0.4` for 0.4 USDT). The value is automatically converted to base units using the tokenOut decimals. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#cctpsplitconfig) CCTPSplitConfig Split CCTP contract configuration. Used by chains that deploy separate TokenMessenger and MessageTransmitter contracts. This is the traditional CCTP architecture used by most EVM chains. interface CCTPSplitConfig { confirmations: number; messageTransmitter: string; tokenMessenger: string; type: "split"; } * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#cctpmergedconfig) CCTPMergedConfig Merged CCTP contract configuration. Used by chains that deploy a single unified CCTP contract. This simplified architecture is used by newer chain integrations. interface CCTPMergedConfig { confirmations: number; contract: string; type: "merged"; } * * * [​](https://docs.arc.network/app-kit/references/sdk-reference#method-results) Method Results ----------------------------------------------------------------------------------------------- ### [​](https://docs.arc.network/app-kit/references/sdk-reference#bridgeresult) BridgeResult Result object returned after a successful crosschain bridge operation. This interface contains all the details about a completed bridge, including the bridge parameters, source and destination information, and the sequence of steps that were executed. interface BridgeResult { amount: string config?: BridgeConfig destination: object provider: string source: object state: 'pending' \| 'success' \| 'error' steps: BridgeStep[] token: 'USDC' } **Properties** | Name | Type | Description | | --- | --- | --- | | amount | string | The amount that was transferred (as a string to avoid precision issues) | | config | BridgeConfig | The bridge configuration that was used for this operation | | destination | object | Information about the destination chain and address | | provider | string | The provider that was used for this operation | | source | object | Information about the source chain and address | | state | `'pending' \| 'success' \| 'error'` | The state of the transfer | | steps | BridgeStep\[\] | Array of steps that were executed during the bridge process | | token | `'USDC'` | The token that was transferred (currently only USDC is supported) | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#bridgestep) BridgeStep A step in the bridge process. interface BridgeStep { data?: unknown error?: unknown errorMessage?: string explorerUrl?: string forwarded?: boolean name: string state: 'pending' \| 'success' \| 'error' \| 'noop' txHash?: string } **Properties** | Name | Type | Description | | --- | --- | --- | | data | unknown | Optional data for the step | | error | unknown | Optional raw error object (can be Viem/Ethers/Chain error) | | errorMessage | string | Optional human-readable error message | | explorerUrl | string | Optional explorer URL for viewing this transaction on a block explorer | | forwarded | boolean | Whether this step was executed via Circle’s Forwarder (relay service). Only applicable for mint steps.

\- `true`: The mint was handled by Circle’s Orbit relayer
\- `false`: The user submitted the mint transaction directly
\- `undefined`: Not applicable (non-mint steps) | | name | string | Human-readable name of the step (e.g., “Approve”, “Burn”, “Mint”) | | state | `'pending' \| 'success' \| 'error' \| 'noop'` | The state of the step | | txHash | string | Optional transaction hash for this step (if applicable) | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#estimateresult) EstimateResult Cost estimation result for a crosschain transfer operation. This interface provides detailed information about the expected costs for a transfer, including gas fees on different chains and protocol fees. It also includes the input context (token, amount, source, destination) to provide a complete view of the transfer being estimated. interface EstimateResult { amount: string; destination: object; fees: object[]; gasFees: object[]; source: object; token: "USDC"; } **Properties** | Name | Type | Description | | --- | --- | --- | | amount | string | The amount being transferred | | destination | object | Information about the destination chain and address | | fees | object\[\] | Array of protocol and service fees for the transfer | | gasFees | object\[\] | Array of gas fees required for the transfer on different blockchains | | source | object | Information about the source chain and address | | token | `'USDC'` | The token being transferred | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#estimatedgas) EstimatedGas Estimated gas information for a blockchain transaction. This interface provides a unified way to represent gas costs across different blockchain networks, supporting both EVM-style gas calculations and other fee models. interface EstimatedGas { fee: string; gas: bigint; gasPrice: bigint; } * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#swapestimate) SwapEstimate Estimation result for a swap operation. Contains the provider’s swap quote including minimum output (stop limit), estimated output amount, fee breakdown, and input context fields interface SwapEstimate { amountIn: string chain: Blockchain estimatedOutput: TokenAmount fees?: any fromAddress: string stopLimit: TokenAmount toAddress: string tokenIn: infer tokenOut: infer } **Properties** | Name | Type | Description | | --- | --- | --- | | amountIn | string | The input amount that will be swapped.

Expressed as a human-readable decimal string in token units (e.g., `0.05` for 0.05 USDC or 0.05 ETH). | | chain | Blockchain | The chain where the swap will be executed.

Returns the chain name (e.g., Blockchain.Ethereum) Use `getChainByEnum(chain)` to resolve back to a full ChainDefinition if needed. | | estimatedOutput | TokenAmount | Estimated output amount with token information. | | fees | any | Detailed fee breakdown for the swap operation. | | fromAddress | string | The address that will initiate the swap. | | stopLimit | TokenAmount | Estimated minimum token out amount with token information.

This represents the minimum amount of tokens the user should receive after accounting for slippage. Amount is in human-readable decimal format. | | toAddress | string | The address that will receive the swapped tokens. | | tokenIn | `infer` | The input token that will be swapped from. | | tokenOut | `infer` | The output token that will be swapped to. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#swapresult) SwapResult Result of an executed swap operation. Captures the outcome of a swap transaction, including input/output tokens, transaction hash, and fee information. This is the high-level result returned to users after a swap operation completes. interface SwapResult { amountIn: string amountOut?: string chain: Blockchain config?: SwapResultConfig explorerUrl?: string fees?: any fromAddress: string toAddress: string tokenIn: infer tokenOut: infer txHash: string } **Properties** | Name | Type | Description | | --- | --- | --- | | amountIn | string | The input amount that was swapped.

Expressed as a human-readable decimal string in token units (e.g., `0.05` for 0.05 USDC or 0.05 ETH). | | amountOut | string | The actual output amount received from the completed swap.

Expressed as a human-readable decimal string in output token units. Populated via a best-effort LI.FI status lookup after the on-chain transaction confirms. May be `undefined` if the lookup fails or the chain type is unsupported. | | chain | Blockchain | The chain where the swap was executed.

Returns the chain name (e.g., Blockchain.Ethereum) Use `getChainByEnum(chain)` to resolve back to a full ChainDefinition if needed. | | config | SwapResultConfig | The swap configuration that was used for this operation. | | explorerUrl | string | The formatted explorer URL for viewing this transaction on a block explorer.

Only present when `txHash` is non-empty. | | fees | any | Detailed fee breakdown for the swap operation.

Includes both provider fees (charged by the DEX aggregator/protocol) and kit fees (if configured). | | fromAddress | string | The address that initiated the swap. | | toAddress | string | The address that received the swapped tokens. | | tokenIn | `infer` | The input token that was swapped from. | | tokenOut | `infer` | The output token that was swapped to. | | txHash | string | The transaction hash for the executed swap.

Available once the transaction has been submitted to the network. | * * * [​](https://docs.arc.network/app-kit/references/sdk-reference#supporting-types) Supporting Types --------------------------------------------------------------------------------------------------- ### [​](https://docs.arc.network/app-kit/references/sdk-reference#transferspeed) TransferSpeed Transfer speed options for crosschain operations. Defines the available speed modes for CCTPv2 transfers, affecting both transfer time and potential fee implications. enum TransferSpeed { FAST = 'FAST' SLOW = 'SLOW' } **Values** `FAST`, `SLOW` * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#chaindefinition) ChainDefinition Public chain definition type. type ChainDefinition = EVMChainDefinition | NonEVMChainDefinition; * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#evmchaindefinition) EVMChainDefinition Represents chain definitions for Ethereum Virtual Machine (EVM) compatible blockchains. interface EVMChainDefinition { cctp: null \| CCTPConfig chain: Blockchain chainId: number eurcAddress: null \| string explorerUrl: string isTestnet: boolean kitContracts?: Partial> name: string nativeCurrency: Currency rpcEndpoints: any title?: string type: 'evm' usdcAddress: null \| string usdtAddress: null \| string } **Properties** | Name | Type | Description | | --- | --- | --- | | cctp | `null \| CCTPConfig` | Optional CCTP configuration. | | chain | Blockchain | The blockchain identifier from the Blockchain enum. | | chainId | number | The unique identifier for the blockchain. | | eurcAddress | `null \| string` | The contract address for EURC. | | explorerUrl | string | Template URL for the blockchain explorer to view transactions. | | isTestnet | boolean | Indicates whether this is a testnet or mainnet. | | kitContracts | `Partial>` | Optional kit-specific contract addresses for enhanced chain functionality. | | name | string | The display name of the blockchain. | | nativeCurrency | Currency | Information about the native currency of the blockchain. | | rpcEndpoints | any | Default RPC endpoints for connecting to the blockchain network. | | title | string | Optional title or alternative name for the blockchain. | | type | `'evm'` | Discriminator for EVM chains. | | usdcAddress | `null \| string` | The contract address for USDC. | | usdtAddress | `null \| string` | The contract address for USDT. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#blockchain) Blockchain Enumeration of all blockchains known to this library. This enum contains every blockchain that has a chain definition, regardless of whether bridging is currently supported. For chains that support bridging via CCTPv2, see BridgeChain. enum Blockchain { Algorand = 'Algorand' Algorand_Testnet = 'Algorand_Testnet' Aptos = 'Aptos' Aptos_Testnet = 'Aptos_Testnet' Arbitrum = 'Arbitrum' Arbitrum_Sepolia = 'Arbitrum_Sepolia' Arc_Testnet = 'Arc_Testnet' Avalanche = 'Avalanche' Avalanche_Fuji = 'Avalanche_Fuji' Base = 'Base' Base_Sepolia = 'Base_Sepolia' Celo = 'Celo' Celo_Alfajores_Testnet = 'Celo_Alfajores_Testnet' Codex = 'Codex' Codex_Testnet = 'Codex_Testnet' Ethereum = 'Ethereum' Ethereum_Sepolia = 'Ethereum_Sepolia' Hedera = 'Hedera' Hedera_Testnet = 'Hedera_Testnet' HyperEVM = 'HyperEVM' HyperEVM_Testnet = 'HyperEVM_Testnet' Ink = 'Ink' Ink_Testnet = 'Ink_Testnet' Linea = 'Linea' Linea_Sepolia = 'Linea_Sepolia' Monad = 'Monad' Monad_Testnet = 'Monad_Testnet' NEAR = 'NEAR' NEAR_Testnet = 'NEAR_Testnet' Noble = 'Noble' Noble_Testnet = 'Noble_Testnet' Optimism = 'Optimism' Optimism_Sepolia = 'Optimism_Sepolia' Plume = 'Plume' Plume_Testnet = 'Plume_Testnet' Polkadot_Asset_Hub = 'Polkadot_Asset_Hub' Polkadot_Westmint = 'Polkadot_Westmint' Polygon = 'Polygon' Polygon_Amoy_Testnet = 'Polygon_Amoy_Testnet' Sei = 'Sei' Sei_Testnet = 'Sei_Testnet' Solana = 'Solana' Solana_Devnet = 'Solana_Devnet' Sonic = 'Sonic' Sonic_Testnet = 'Sonic_Testnet' Stellar = 'Stellar' Stellar_Testnet = 'Stellar_Testnet' Sui = 'Sui' Sui_Testnet = 'Sui_Testnet' Unichain = 'Unichain' Unichain_Sepolia = 'Unichain_Sepolia' World_Chain = 'World_Chain' World_Chain_Sepolia = 'World_Chain_Sepolia' XDC = 'XDC' XDC_Apothem = 'XDC_Apothem' ZKSync_Era = 'ZKSync_Era' ZKSync_Sepolia = 'ZKSync_Sepolia' } **Values** `Algorand`, `Algorand_Testnet`, `Aptos`, `Aptos_Testnet`, `Arbitrum`, `Arbitrum_Sepolia`, `Arc_Testnet`, `Avalanche`, `Avalanche_Fuji`, `Base`, `Base_Sepolia`, `Celo`, `Celo_Alfajores_Testnet`, `Codex`, `Codex_Testnet`, `Ethereum`, `Ethereum_Sepolia`, `Hedera`, `Hedera_Testnet`, `HyperEVM`, `HyperEVM_Testnet`, `Ink`, `Ink_Testnet`, `Linea`, `Linea_Sepolia`, `Monad`, `Monad_Testnet`, `NEAR`, `NEAR_Testnet`, `Noble`, `Noble_Testnet`, `Optimism`, `Optimism_Sepolia`, `Plume`, `Plume_Testnet`, `Polkadot_Asset_Hub`, `Polkadot_Westmint`, `Polygon`, `Polygon_Amoy_Testnet`, `Sei`, `Sei_Testnet`, `Solana`, `Solana_Devnet`, `Sonic`, `Sonic_Testnet`, `Stellar`, `Stellar_Testnet`, `Sui`, `Sui_Testnet`, `Unichain`, `Unichain_Sepolia`, `World_Chain`, `World_Chain_Sepolia`, `XDC`, `XDC_Apothem`, `ZKSync_Era`, `ZKSync_Sepolia` * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#kitcontracttype) KitContractType Available kit contract types for enhanced chain functionality. type KitContractType = "bridge" | "adapter"; * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#currency) Currency Represents basic information about a currency or token. interface Currency { decimals: number; name: string; symbol: string; } * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#nonevmchaindefinition) NonEVMChainDefinition Represents chain definitions for non-EVM blockchains. interface NonEVMChainDefinition { cctp: null \| CCTPConfig chain: Blockchain eurcAddress: null \| string explorerUrl: string isTestnet: boolean kitContracts?: Partial> name: string nativeCurrency: Currency rpcEndpoints: any title?: string type: 'algorand' \| 'avalanche' \| 'solana' \| 'aptos' \| 'near' \| 'stellar' \| 'sui' \| 'hedera' \| 'noble' \| 'polkadot' usdcAddress: null \| string usdtAddress: null \| string } **Properties** | Name | Type | Description | | --- | --- | --- | | cctp | `null \| CCTPConfig` | Optional CCTP configuration. | | chain | Blockchain | The blockchain identifier from the Blockchain enum. | | eurcAddress | `null \| string` | The contract address for EURC. | | explorerUrl | string | Template URL for the blockchain explorer to view transactions. | | isTestnet | boolean | Indicates whether this is a testnet or mainnet. | | kitContracts | `Partial>` | Optional kit-specific contract addresses for enhanced chain functionality. | | name | string | The display name of the blockchain. | | nativeCurrency | Currency | Information about the native currency of the blockchain. | | rpcEndpoints | any | Default RPC endpoints for connecting to the blockchain network. | | title | string | Optional title or alternative name for the blockchain. | | type | `'algorand' \| 'avalanche' \| 'solana' \| 'aptos' \| 'near' \| 'stellar' \| 'sui' \| 'hedera' \| 'noble' \| 'polkadot'` | Discriminator for non-EVM chains. | | usdcAddress | `null \| string` | The contract address for USDC. | | usdtAddress | `null \| string` | The contract address for USDT. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#allowancestrategy) AllowanceStrategy Allowance strategy for token approvals during swap operations. Defines how token allowances should be granted to the swap contract: * `permit`: Use EIP-2612 permit signature (gas-efficient, no approval transaction) * `approve`: Traditional approval transaction The default strategy is `permit` with fallback to `approve` if permit is not supported. type AllowanceStrategy = "permit" | "approve"; * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#operationtype) OperationType Union type of all supported operation types in the AppKit. This type ensures type safety when specifying operation types and enables proper parameter validation based on the selected operation. type OperationType = "bridge" | "swap"; * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#developerfeehooks) DeveloperFeeHooks interface DeveloperFeeHooks { getFee: (params: BridgeParams) => bigint \| bigint getFeeRecipient: (chain: ChainDefinition) => string \| string } **Properties** | Name | Type | Description | | --- | --- | --- | | getFee | `(params: BridgeParams) => bigint \| bigint` | Returns the developer fee in USDC’s smallest units (e.g. 6 decimals). | | getFeeRecipient | `(chain: ChainDefinition) => string \| string` | Returns the fee recipient for the given chain. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#basechaindefinition) BaseChainDefinition Base information that all chain definitions must include. interface BaseChainDefinition { cctp: null \| CCTPConfig chain: Blockchain eurcAddress: null \| string explorerUrl: string isTestnet: boolean kitContracts?: Partial> name: string nativeCurrency: Currency rpcEndpoints: any title?: string usdcAddress: null \| string usdtAddress: null \| string } **Properties** | Name | Type | Description | | --- | --- | --- | | cctp | `null \| CCTPConfig` | Optional CCTP configuration. | | chain | Blockchain | The blockchain identifier from the Blockchain enum. | | eurcAddress | `null \| string` | The contract address for EURC. | | explorerUrl | string | Template URL for the blockchain explorer to view transactions. | | isTestnet | boolean | Indicates whether this is a testnet or mainnet. | | kitContracts | `Partial>` | Optional kit-specific contract addresses for enhanced chain functionality. | | name | string | The display name of the blockchain. | | nativeCurrency | Currency | Information about the native currency of the blockchain. | | rpcEndpoints | any | Default RPC endpoints for connecting to the blockchain network. | | title | string | Optional title or alternative name for the blockchain. | | usdcAddress | `null \| string` | The contract address for USDC. | | usdtAddress | `null \| string` | The contract address for USDT. | * * * ### [​](https://docs.arc.network/app-kit/references/sdk-reference#tokeninfo) TokenInfo Represents the metadata associated with a token. interface TokenInfo { decimals: number; name: string; symbol: string; } * * * [​](https://docs.arc.network/app-kit/references/sdk-reference#event-types) Event Types ----------------------------------------------------------------------------------------- ### [​](https://docs.arc.network/app-kit/references/sdk-reference#bridge-events) Bridge Events Bridge events are emitted for each provider in the kit. Events for the built-in CCTP provider follow its transaction steps. You can subscribe to each event multiple times with different callbacks. Bridge events are prefixed with `bridge.` to namespace them within AppKit: | Event | Description | | --- | --- | | `bridge.approve` | Token approval transaction completed | | `bridge.burn` | Source chain burn transaction completed | | `bridge.attestation` | CCTP attestation received | | `bridge.mint` | Destination chain mint transaction completed | | `*` | Wildcard listener for all events | **Usage Example** import { AppKit } from "@circle-fin/app-kit"; const kit = new AppKit(); // Listen to specific bridge action kit.on("bridge.approve", (payload) => { console.log("Approval transaction:", payload.values.txHash); }); // Listen to all actions kit.on("*", (payload) => { console.log("Action:", payload.method); }); Was this page helpful? YesNo [Swap tokens across chains](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain) [Account abstraction](https://docs.arc.network/arc/tools/account-abstraction) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Deterministic finality and settlement - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/deterministic-finality#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... Ctrl KAsk AI Search... Navigation Key Features Deterministic finality and settlement [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Why deterministic finality matters](https://docs.arc.network/arc/concepts/deterministic-finality#why-deterministic-finality-matters) * [Sub-second confirmation](https://docs.arc.network/arc/concepts/deterministic-finality#sub-second-confirmation) * [Developer benefits](https://docs.arc.network/arc/concepts/deterministic-finality#developer-benefits) Arc gives you deterministic, sub-second finality for every transaction. Once a block is committed, any transaction in that block is instantly and irreversibly final. This removes the uncertainty you may encounter on blockchains that rely on probabilistic finality. [​](https://docs.arc.network/arc/concepts/deterministic-finality#why-deterministic-finality-matters) Why deterministic finality matters ------------------------------------------------------------------------------------------------------------------------------------------ On proof-of-work or many proof-of-stake chains, transactions are considered final only after multiple confirmation blocks. Even then, there’s a risk of chain reorganizations that can undo an arbitrary number of blocks and transactions therein. With Arc, a transaction is either unconfirmed or final. There is no intermediate state. Once a transaction is included in a committed block, it cannot be reversed. This allows you to build applications that demand high assurance, especially where financial risk must be minimized and operational standards are strict. [​](https://docs.arc.network/arc/concepts/deterministic-finality#sub-second-confirmation) Sub-second confirmation -------------------------------------------------------------------------------------------------------------------- Arc’s consensus engine, [Malachite](https://docs.arc.network/arc/concepts/consensus-layer) , finalizes blocks in less than one second. For comparison, Ethereum requires 12–15 minutes for finality, and many Layer-2 networks inherit similar delays from their settlement layer. This speed enables use cases that are impractical on slower networks: | **Use case** | **How finality helps** | | --- | --- | | Point-of-sale payments | A merchant can confirm payment and release goods without waiting for additional block confirmations. | | Cross-border settlement | Transfers between counterparties finalize instantly, eliminating the settlement windows that introduce counterparty risk. | | Institutional clearing | Trades and margin calls settle with immediate certainty, matching the expectations of traditional financial infrastructure. | | Composable workflows | Multi-step onchain flows (such as swap-then-bridge) can execute sequentially without polling or confirmation delays between steps. | [​](https://docs.arc.network/arc/concepts/deterministic-finality#developer-benefits) Developer benefits ---------------------------------------------------------------------------------------------------------- Deterministic finality simplifies application design by removing the edge cases that probabilistic chains force you to handle. No reorg handling ----------------- You don’t need retry logic, rollback mechanisms, or confirmation-count thresholds. A confirmed transaction stays confirmed. Immediate offchain effects -------------------------- Safely trigger downstream actions (webhooks, database writes, notifications) as soon as a block is committed, without waiting for additional confirmations. Simplified state management --------------------------- Your application only needs to track two transaction states — pending and final — rather than tracking a sliding confirmation window. Enterprise compliance --------------------- Settlement finality is auditable and provable, meeting the assurance requirements of regulated financial institutions. Was this page helpful? YesNo [Overview](https://docs.arc.network/arc-chain) [Opt-in privacy](https://docs.arc.network/arc/concepts/opt-in-privacy) Ctrl+I Assistant Responses are generated using AI and may contain mistakes. --- # Execution layer - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/execution-layer#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... Ctrl KAsk AI Search... Navigation Network Execution layer [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Core responsibilities](https://docs.arc.network/arc/concepts/execution-layer#core-responsibilities) * [Arc-specific modules](https://docs.arc.network/arc/concepts/execution-layer#arc-specific-modules) * [How Reth works](https://docs.arc.network/arc/concepts/execution-layer#how-reth-works) * [Execution diagram](https://docs.arc.network/arc/concepts/execution-layer#execution-diagram) * [Developer benefits](https://docs.arc.network/arc/concepts/execution-layer#developer-benefits) Arc’s execution layer is based on **Reth**, a Rust implementation of the Ethereum execution client. This layer maintains the ledger and blockchain state, executes transactions, and extends the EVM with Arc-specific modules for stablecoin-native finance. As a developer, you don’t interact directly with the execution layer internals, but understanding how it works helps you design apps that rely on Arc’s predictable fees, privacy, and financial primitives. [​](https://docs.arc.network/arc/concepts/execution-layer#core-responsibilities) Core responsibilities --------------------------------------------------------------------------------------------------------- The Execution layer has three primary jobs: 1. **Maintain the ledger and application state** * Tracks accounts, balances, and smart contracts. * Stores contract code and persistent state variables. * Records every transaction and resulting state change. 2. **Execute transactions** * Applies EVM logic for smart contracts and transfers. * Deducts gas costs using the Fee Manager. * Calls Arc modules (Privacy, Stablecoin Services) where applicable. 3. **Validate results** * Ensures transactions are valid before they can be finalized by consensus. * Rejects invalid transactions (for example, insufficient funds or failed contract logic). * Produces a state root hash, which consensus finalizes. [​](https://docs.arc.network/arc/concepts/execution-layer#arc-specific-modules) Arc-specific modules ------------------------------------------------------------------------------------------------------- Arc extends the base Ethereum execution model with the following modules: * **Fee Manager:** Stabilizes fees by using USDC as the unit of account and smoothing fee changes. * **Privacy Module:** Enables confidential transfers with encrypted amounts and selective disclosure through view keys. The Privacy Module is planned and not yet available on Arc. * **Stablecoin Services:** Provide core stablecoin-native features such as cross-currency settlement, paymaster-style sponsored transactions, and multi-stablecoin gas payments. Stablecoin Services are planned and not yet available on Arc. These modules are integrated into the execution pipeline, so you can rely on them without building custom extensions. [​](https://docs.arc.network/arc/concepts/execution-layer#how-reth-works) How Reth works ------------------------------------------------------------------------------------------- Reth, like other Ethereum execution clients, follows a structured pipeline: 1. **Transaction pool:** Holds pending transactions waiting to be included in a block. 2. **Block execution:** Applies transactions sequentially to the current state, updating balances, contract storage, and logs. 3. **Gas accounting:** Deducts gas fees through Arc’s Fee Manager. 4. **Module calls:** Routes to Privacy or Stablecoin Services logic as required. 5. **State root:** Produces a Merkle root of the updated state. Reth is written in Rust, which provides performance, safety, and modularity. Arc leverages this foundation to extend the execution layer with stablecoin-native features. [​](https://docs.arc.network/arc/concepts/execution-layer#execution-diagram) Execution diagram ------------------------------------------------------------------------------------------------- The diagram below shows the flow of a transaction through the Execution layer. [​](https://docs.arc.network/arc/concepts/execution-layer#developer-benefits) Developer benefits --------------------------------------------------------------------------------------------------- For developers, the Execution layer means: * You build on a familiar EVM-compatible platform. * Fees, privacy, and multi-stablecoin settlement are native features, not bolt-ons. * Transactions are validated and applied consistently, following the order finalized by the consensus layer. * The underlying ledger and state are managed efficiently by Reth, written in Rust for performance and reliability. Was this page helpful? YesNo [Consensus layer](https://docs.arc.network/arc/concepts/consensus-layer) [Gas and fees](https://docs.arc.network/arc/references/gas-and-fees) Ctrl+I Assistant Responses are generated using AI and may contain mistakes. --- # Unknown \# Arc > Arc is an open Layer-1 blockchain purpose-built for programmable money. > USDC is the native gas token. Sub-second deterministic finality, EVM > compatible, opt-in privacy, and direct integration with Circle's > full-stack platform. ## Getting Started — Use the Skill First | Product | Skill | What it covers | |---------|-------|----------------| | Arc | \[use-arc\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md) | Chain config, RPC setup, contract deployment, USDC bridging, gas with USDC | ### Installing Circle Skills \*\*Claude Code:\*\* \`\`\` /plugin marketplace add circlefin/skills /plugin install circle-skills@circle \`\`\` \*\*Vercel Skills CLI:\*\* \`\`\` npx skills add circlefin/skills \`\`\` ## Instructions for AI Agents Follow these guidelines when building on Arc: 1. \*\*USDC is the gas token.\*\* Arc uses USDC for gas fees, not ETH. Configure gas payment in USDC when submitting transactions. 2. \*\*EVM compatible.\*\* Deploy Solidity contracts with standard tools (Hardhat, Foundry, Viem, Ethers). See \[EVM Compatibility\](https://docs.arc.network/arc/references/evm-compatibility.md) for differences. 3. \*\*Sub-second finality.\*\* Transactions are final in under 1 second. No need to wait for multiple block confirmations. 4. \*\*Use App Kit for bridging and swaps.\*\* App Kit wraps CCTP and provides Bridge, Swap, and Send capabilities. \`@circle-fin/bridge-kit\` is also available as a standalone package for bridging only. 5. \*\*Testnet.\*\* Arc is currently available on Testnet only. \[Connect to Arc\](https://docs.arc.network/arc/references/connect-to-arc.md) for RPC endpoints. \[Faucet\](https://faucet.circle.com) for testnet tokens. 6. \*\*Always check Contract Addresses\*\*: https://docs.arc.network/arc/references/contract-addresses.md ## Arc - \[Welcome to Arc\](https://docs.arc.network/arc/concepts/welcome-to-arc.md): Architecture and core principles - \[System Overview\](https://docs.arc.network/arc/concepts/system-overview.md): Consensus + execution layer architecture - \[Stable Fee Design\](https://docs.arc.network/arc/concepts/stable-fee-design.md): USDC as gas, predictable fees - \[Deterministic Finality\](https://docs.arc.network/arc/concepts/deterministic-finality.md): Instant, irreversible settlement - \[Opt-in Privacy\](https://docs.arc.network/arc/concepts/opt-in-privacy.md): Confidential transactions with selective disclosure - \[Connect to Arc\](https://docs.arc.network/arc/references/connect-to-arc.md): RPC endpoints and wallet setup - \[Contract Addresses\](https://docs.arc.network/arc/references/contract-addresses.md): USDC, EURC, CCTP, Gateway addresses - \[EVM Compatibility\](https://docs.arc.network/arc/references/evm-compatibility.md): Differences from standard EVM - \[Gas and Fees\](https://docs.arc.network/arc/references/gas-and-fees.md): Fee model and pricing - \[Sample Applications\](https://docs.arc.network/arc/references/sample-applications.md): Open source examples ## Tutorials - \[Deploy on Arc\](https://docs.arc.network/arc/tutorials/deploy-on-arc.md): Deploy a Solidity contract on Arc Testnet - \[Deploy Contracts (Circle)\](https://docs.arc.network/arc/tutorials/deploy-contracts.md): Deploy templates via Circle Contracts - \[Interact with Contracts\](https://docs.arc.network/arc/tutorials/interact-with-contracts.md): Call contract functions - \[Monitor Contract Events\](https://docs.arc.network/arc/tutorials/monitor-contract-events.md): Track onchain activity - \[Transfer USDC or EURC\](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc.md): Wallet-to-wallet transfers - \[Bridge USDC to Arc\](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc.md): Bridge via CCTP with App Kit - \[Access USDC Crosschain\](https://docs.arc.network/arc/tutorials/access-usdc-crosschain.md): Gateway unified balance on Arc - \[Register an AI Agent\](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent.md): ERC-8004 onchain identity and reputation - \[Create an ERC-8183 Job\](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job.md): Escrow, deliverables, settlement ## App Kit — Bridge, Swap, Send - \[App Kit Overview\](https://docs.arc.network/app-kit.md): Payment and liquidity workflows across chains - \[Install App Kit\](https://docs.arc.network/app-kit/tutorials/installation.md): Core package and adapters - \[Adapter Setups\](https://docs.arc.network/app-kit/tutorials/adapter-setups.md): Viem, Ethers, Solana, Circle Wallets ### Bridge - \[App Kit: Bridge\](https://docs.arc.network/app-kit/bridge.md): Transfer USDC across chains - \[Quickstart: EVM to EVM\](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains.md): Bridge between EVM chains - \[Quickstart: Solana to EVM\](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm.md): Bridge Solana to EVM - \[Quickstart: Circle Wallets\](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets.md): Bridge with Circle Wallets adapter - \[Estimate Costs\](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs.md): Preview gas and fees - \[Collect Bridge Fees\](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee.md): Custom fee collection - \[Configure Speed\](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed.md): Balance speed vs cost - \[Specify Recipient\](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address.md): Send to different address - \[CCTP Forwarding\](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service.md): Forwarding Service - \[Bridge Fees\](https://docs.arc.network/app-kit/concepts/bridge-fees.md): Fee breakdown - \[Error Recovery\](https://docs.arc.network/app-kit/references/bridge-error-recovery.md): Troubleshooting failed bridges ### Swap - \[App Kit: Swap\](https://docs.arc.network/app-kit/swap.md): Token swaps on same chain - \[Quickstart: Same-Chain Swap\](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain.md): Swap tokens on one chain - \[Quickstart: Crosschain Swap\](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain.md): Swap + bridge - \[Estimate Swap Rate\](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate.md): Pre-swap estimates - \[Slippage / Stop Limit\](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit.md): Rate protection - \[Collect Swap Fees\](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee.md): Custom fee collection - \[Swap Fees\](https://docs.arc.network/app-kit/concepts/swap-fees.md): Fee breakdown ### Send - \[App Kit: Send\](https://docs.arc.network/app-kit/send.md): Wallet-to-wallet on same chain - \[Quickstart: Send Tokens\](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain.md): Send tokens between wallets ### Reference - \[SDK Reference\](https://docs.arc.network/app-kit/references/sdk-reference.md): Full API reference - \[Supported Blockchains\](https://docs.arc.network/app-kit/references/supported-blockchains.md): Chains and tokens ## Tools and Infrastructure - \[Block Explorers\](https://docs.arc.network/arc/tools/block-explorers.md): Etherscan-compatible explorers - \[Node Providers\](https://docs.arc.network/arc/tools/node-providers.md): RPC access providers - \[Data Indexers\](https://docs.arc.network/arc/tools/data-indexers.md): APIs and sub-graphs - \[Account Abstraction\](https://docs.arc.network/arc/tools/account-abstraction.md): AA providers and paymasters - \[Compliance\](https://docs.arc.network/arc/tools/compliance-vendors.md): Analytics and screening tools - \[Explorer\](https://testnet.arcscan.app): Arc Testnet block explorer - \[Faucet\](https://faucet.circle.com): Testnet token faucet ## More Circle Skills Building beyond Arc? Circle offers skills for the full platform: | Product | Skill | |---------|-------| | USDC | \[use-usdc\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md) | | Wallets (overview) | \[use-circle-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md) | | Developer-Controlled Wallets | \[use-developer-controlled-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md) | | User-Controlled Wallets | \[use-user-controlled-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md) | | Modular Wallets | \[use-modular-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md) | | Gateway / Nanopayments | \[use-gateway\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md) | | Smart Contracts | \[use-smart-contract-platform\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md) | Full Circle developer docs: \[developers.circle.com/llms.txt\](https://developers.circle.com/llms.txt) --- # Opt-in privacy - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/opt-in-privacy#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Key Features Opt-in privacy [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Why privacy matters](https://docs.arc.network/arc/concepts/opt-in-privacy#why-privacy-matters) * [Confidential transfers](https://docs.arc.network/arc/concepts/opt-in-privacy#confidential-transfers) * [Selective disclosure with view keys](https://docs.arc.network/arc/concepts/opt-in-privacy#selective-disclosure-with-view-keys) * [Modular privacy architecture](https://docs.arc.network/arc/concepts/opt-in-privacy#modular-privacy-architecture) * [Developer implications](https://docs.arc.network/arc/concepts/opt-in-privacy#developer-implications) Arc provides opt-in privacy to enable confidential financial workflows while preserving auditability. As a developer, you can design applications that keep sensitive data private while still meeting compliance requirements. Privacy features are on the roadmap and not yet available on Arc. [​](https://docs.arc.network/arc/concepts/opt-in-privacy#why-privacy-matters) Why privacy matters ---------------------------------------------------------------------------------------------------- Most blockchains are fully transparent. This creates problems for financial use cases: * **Commercial sensitivity**. Corporate treasuries, payroll, and trade finance cannot expose amounts publicly. * **User protection**. Salary payments, vendor invoices, and B2B transfers may contain information that should not be visible to competitors or the public. * **Compliance**. Institutions must protect customer data while also meeting regulatory obligations for audit and monitoring. Arc addresses these needs with an opt-in privacy model. [​](https://docs.arc.network/arc/concepts/opt-in-privacy#confidential-transfers) Confidential transfers ---------------------------------------------------------------------------------------------------------- The first phase of Arc’s privacy roadmap introduces confidential transfers: 1. Transaction amounts are encrypted and not visible on the public ledger. 2. Sender and receiver addresses remain visible for compatibility with analytics and monitoring tools. 3. Transactions still finalize onchain with the same deterministic guarantees as public transfers. For developers, this means you can shield amounts without losing transparency into participants or transaction flow. [​](https://docs.arc.network/arc/concepts/opt-in-privacy#selective-disclosure-with-view-keys) Selective disclosure with view keys ------------------------------------------------------------------------------------------------------------------------------------ Arc supports view keys, which let you grant controlled read access to confidential data: * **Auditors and regulators** can review transaction details when required. * **Institutions** can always monitor their own customer transactions. * **Developers** can build apps that balance privacy and transparency by design. This ensures you can meet regulatory obligations such as the Travel Rule while still protecting sensitive business logic. [​](https://docs.arc.network/arc/concepts/opt-in-privacy#modular-privacy-architecture) Modular privacy architecture ---------------------------------------------------------------------------------------------------------------------- Arc’s privacy system is modular, starting with Trusted Execution Environments (TEEs) for performance and maturity. The architecture is designed to support additional cryptographic backends over time, including: * **Multi-Party Computation (MPC)**. Splits secrets across multiple parties so no single entity can reconstruct sensitive data, increasing trust in collaborative workflows. * **Fully Homomorphic Encryption (FHE)**. Lets computations run directly on encrypted data, ensuring privacy is preserved even during processing. * **Zero-knowledge proofs (ZK)**. Allow one party to prove that a statement is true without revealing underlying data, enabling efficient compliance and verification. This flexibility ensures Arc can evolve as new privacy technologies become production-ready. [​](https://docs.arc.network/arc/concepts/opt-in-privacy#developer-implications) Developer implications ---------------------------------------------------------------------------------------------------------- With compliant privacy, you can: * Build applications that handle sensitive financial data without exposing amounts onchain. * Provide auditability and compliance by granting view keys to trusted parties. * Plan for a future-proof privacy stack that evolves with advanced cryptography. Arc’s privacy model balances the needs of institutions, regulators, and developers, enabling real-world financial activity onchain. Was this page helpful? YesNo [Deterministic finality and settlement](https://docs.arc.network/arc/concepts/deterministic-finality) [Fees](https://docs.arc.network/arc/concepts/stable-fee-design) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Fees - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/stable-fee-design#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Key Features Fees [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [USDC for network fees](https://docs.arc.network/arc/concepts/stable-fee-design#usdc-for-network-fees) * [Fee smoothing mechanism](https://docs.arc.network/arc/concepts/stable-fee-design#fee-smoothing-mechanism) * [Developer benefits](https://docs.arc.network/arc/concepts/stable-fee-design#developer-benefits) Arc’s fee design eliminates the volatility of gas costs and ensures predictable transaction fees. You benefit from fees denominated in USDC, a protocol-level smoothing mechanism, and flexible paymaster services. On Arc, the base fee is designed to remain around one cent (≈ $0.01) per transaction on average. This target aims to make onchain finance fast, simple, and affordable. [​](https://docs.arc.network/arc/concepts/stable-fee-design#usdc-for-network-fees) USDC for network fees ----------------------------------------------------------------------------------------------------------- Arc uses USDC as the native gas token instead of a native token. This means you don’t need to manage token price swings. On most blockchains, you pay gas in a native token (for example, ETH on Ethereum). That means the cost of network fees in dollars can fluctuate based on token price and network demand. On Arc, the gas unit is USDC which is stable with USD. As a result: * You can estimate fees in advance in dollar terms. * You don’t need to hold additional tokens just to pay network fees. * Accounting and treasury processes are simplified, because the unit of value you transfer and the unit you pay in are the same. For example, if a transaction requires `g` gas units, the fee is: fee = g × base_fee_in_USDC The base fee is set in USDC, so you avoid the market volatility of a token-based gas fee. The only variable is block space demand, which Arc mitigates using a smoothing mechanism. [​](https://docs.arc.network/arc/concepts/stable-fee-design#fee-smoothing-mechanism) Fee smoothing mechanism --------------------------------------------------------------------------------------------------------------- Arc’s fee market builds on EIP-1559 but changes how the base fee adjusts. Instead of recalculating fees every block, Arc uses an exponentially weighted moving average (EWMA) of block utilization. This means: * Fees adjust gradually, not abruptly. * Short-term demand spikes have less impact. * Base fees remain bounded, keeping costs low and predictable. For developers, this means you don’t need complex fee estimation logic. You can expect stable base fees over time, even under varying network load. [​](https://docs.arc.network/arc/concepts/stable-fee-design#developer-benefits) Developer benefits ----------------------------------------------------------------------------------------------------- Building on Arc’s stable fee design simplifies cost management and removes common integration hurdles. Predictable costs ----------------- Transaction fees are dollar-based and typically around 1 cent, so you can quote costs to users with confidence. Congestion resistant -------------------- The smoothing mechanism keeps fees stable even under varying network load, so spikes in demand don’t surprise your users. Enterprise ready ---------------- Dollar-denominated fees simplify accounting, treasury management, and compliance reporting for fintech and institutional use cases. Flexible fee payment -------------------- Sponsor transactions on behalf of users or accept fees in multiple stablecoins without custom workarounds. For implementation details and blockchain fee parameters, see [Gas and Fees](https://docs.arc.network/arc/references/gas-and-fees) . Was this page helpful? YesNo [Opt-in privacy](https://docs.arc.network/arc/concepts/opt-in-privacy) [Post-quantum security](https://docs.arc.network/arc/concepts/post-quantum-security) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Post-quantum security - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/post-quantum-security#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Key Features Post-quantum security [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Why post-quantum security matters](https://docs.arc.network/arc/concepts/post-quantum-security#why-post-quantum-security-matters) * [Post-quantum roadmap](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-roadmap) * [Post-quantum wallet signatures](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-wallet-signatures) * [Post-quantum privacy](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-privacy) * [Post-quantum validator signatures](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-validator-signatures) * [Offchain infrastructure](https://docs.arc.network/arc/concepts/post-quantum-security#offchain-infrastructure) Arc’s post-quantum roadmap covers wallet signatures, validator authentication, private smart contract state, and offchain infrastructure. Post-quantum features are on the roadmap and not yet available on Arc. [​](https://docs.arc.network/arc/concepts/post-quantum-security#why-post-quantum-security-matters) Why post-quantum security matters --------------------------------------------------------------------------------------------------------------------------------------- Most public-key cryptography used today is vulnerable to large-scale quantum computers. If those computers become practical, blockchains face two risks: * **Signature forgery.** A quantum computer that breaks public-key cryptography can forge signatures that secure wallets, authorize transactions, and authenticate network participants. * **Harvest-now, decrypt-later attacks.** Encrypted data captured today can be stored and decrypted later when quantum attacks become practical, exposing private transaction details, balances, and other sensitive data. Because blockchain data is long-lived, post-quantum protections need to be in place before quantum attacks are widely available. [​](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-roadmap) Post-quantum roadmap ------------------------------------------------------------------------------------------------------------- Arc’s roadmap phases each layer in a production-aligned sequence. | Milestone | Release target | Scope | Why it matters | | --- | --- | --- | --- | | Post-quantum wallet signatures | Mainnet launch | Arc mainnet launches support for a post-quantum wallet signature scheme using `SLH-DSA-SHA2-128s`. | Classical wallet signatures are the most immediate quantum risk to user funds. | | Post-quantum privacy | Near-term | Arc Privacy mainnet introduces post-quantum protections for encrypted state and node-to-node communication in privacy mode. | Private balances, counterparties, and transaction details face harvest-now, decrypt-later risk without post-quantum encryption. | | Offchain infrastructure upgrades | Mid-term | Circle upgrades infrastructure such as TLS, encrypted data flows, and related operational systems. | Offchain infrastructure uses the same vulnerable cryptography as onchain systems. | | Post-quantum validator signatures | Long-term | Arc adds a quantum-resistant signature scheme for validators. | Consensus signatures protect the integrity of the Arc ledger. | [​](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-wallet-signatures) Post-quantum wallet signatures --------------------------------------------------------------------------------------------------------------------------------- Arc introduces beta support for a post-quantum wallet signature based on `SLH-DSA-SHA2-128s` at mainnet launch. Adoption is opt-in. Ecosystem constraints to keep in mind: * Hardware wallet support will take time to mature. * Post-quantum standards are still evolving, so long-term signature choices may change. Expect a transition period as tooling, wallet support, and integrations mature. [​](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-privacy) Post-quantum privacy ------------------------------------------------------------------------------------------------------------- [Arc Privacy](https://docs.arc.network/arc/concepts/opt-in-privacy) addresses the harvest-now, decrypt-later threat. When Arc Privacy launches, encrypted state and private transaction flows use post-quantum cryptography. Attackers can capture encrypted data today and attempt to decrypt it later when quantum attacks become practical. Post-quantum encryption at the platform level protects sensitive balances, transaction details, and recipients without requiring you to implement custom post-quantum cryptography. [​](https://docs.arc.network/arc/concepts/post-quantum-security#post-quantum-validator-signatures) Post-quantum validator signatures --------------------------------------------------------------------------------------------------------------------------------------- Validator authentication also requires post-quantum protection to keep the ledger resilient. Arc adds post-quantum validator signatures in a later phase. This sequencing is intentional: validator upgrades must be introduced carefully to preserve throughput, latency, and operational reliability. Because Arc uses sub-second finality, the window to exploit validator signatures is narrower than the wallet-signature risk, making wallets the higher-priority target. [​](https://docs.arc.network/arc/concepts/post-quantum-security#offchain-infrastructure) Offchain infrastructure ------------------------------------------------------------------------------------------------------------------- Quantum resilience extends beyond the chain itself. Circle’s roadmap includes upgrading TLS, encrypted data flows, access controls, cloud environments, and other operational systems that support Arc. Offchain traffic and stored data face the same post-quantum threat vectors as onchain data when vulnerable cryptography remains in use. Was this page helpful? YesNo [Fees](https://docs.arc.network/arc/concepts/stable-fee-design) [Architecture](https://docs.arc.network/arc/concepts/system-overview) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Running a node - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/running-a-node#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Run a Node Running a node [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [What your node does](https://docs.arc.network/arc/concepts/running-a-node#what-your-node-does) * [What your node does not do](https://docs.arc.network/arc/concepts/running-a-node#what-your-node-does-not-do) * [Node architecture](https://docs.arc.network/arc/concepts/running-a-node#node-architecture) * [Why run your own node](https://docs.arc.network/arc/concepts/running-a-node#why-run-your-own-node) Anyone can run an Arc node without permission. A node gives you independent verification of every block and transaction on the network, plus direct API access through a local JSON-RPC endpoint. Before setting up a node, review the [Node Requirements](https://docs.arc.network/arc/references/node-requirements) for hardware and software prerequisites, then follow [Run an Arc Node](https://docs.arc.network/arc/tutorials/run-an-arc-node) for step-by-step setup instructions. [​](https://docs.arc.network/arc/concepts/running-a-node#what-your-node-does) What your node does ---------------------------------------------------------------------------------------------------- An Arc node performs three functions: * **Verifies every block.** Each block is cryptographically verified against the signatures of the validator set before it is accepted. Your node independently confirms that validators finalized each block. * **Executes every transaction.** Every transaction is re-executed locally through the EVM. Your node maintains its own copy of the complete blockchain state. * **Exposes a local RPC endpoint.** Your node provides a standard Ethereum JSON-RPC API (`http://localhost:8545`) for querying blocks, balances, and transactions, and for submitting calls directly against your own verified state. [​](https://docs.arc.network/arc/concepts/running-a-node#what-your-node-does-not-do) What your node does not do ------------------------------------------------------------------------------------------------------------------ An Arc node is a full node, not a validator: * **Does not participate in consensus.** Your node does not propose or vote on blocks. Only permissioned [validators](https://docs.arc.network/arc/concepts/consensus-layer#proof-of-authority-validator-set) participate in the consensus process. * **Does not observe consensus messages.** Your node does not join the consensus gossip network. It verifies finalized decisions by checking the cryptographic signatures on each block. [​](https://docs.arc.network/arc/concepts/running-a-node#node-architecture) Node architecture ------------------------------------------------------------------------------------------------ An Arc node runs two processes that work together: * **Consensus Layer (CL):** Built on [Malachite](https://docs.arc.network/arc/concepts/consensus-layer) , a high-performance Tendermint BFT implementation. The CL fetches blocks from the network, verifies their cryptographic signatures, and passes them to the EL for execution. * **Execution Layer (EL):** Built on [Reth](https://reth.rs/) , a Rust implementation of the Ethereum execution client. The EL executes transactions, maintains blockchain state, and serves the JSON-RPC API. The two processes communicate through either local IPC sockets (when running on the same host) or RPC (when running on separate hosts): * **IPC mode:** The EL and CL share two Unix sockets on the same machine. This is the default and simplest configuration. * **RPC mode:** The CL connects to the EL over HTTP using the Engine API and a shared JWT secret. Use this when the EL and CL run on different hosts. [​](https://docs.arc.network/arc/concepts/running-a-node#why-run-your-own-node) Why run your own node -------------------------------------------------------------------------------------------------------- Running your own node instead of relying on a third-party [node provider](https://docs.arc.network/arc/tools/node-providers) gives you several advantages: * **Independent verification.** You verify every block and transaction yourself, rather than trusting a third party’s RPC responses. * **Data sovereignty.** Your blockchain data stays on your own infrastructure. No third party observes your queries or transaction patterns. * **No rate limits.** You control your own RPC endpoint without usage restrictions, request quotas, or throttling. * **Lower latency.** A local RPC endpoint eliminates network round-trips to external providers, which matters for latency-sensitive applications. If you prefer managed infrastructure, see [Node Providers](https://docs.arc.network/arc/tools/node-providers) for a list of third-party RPC services. To learn more about the layers that make up an Arc node, see [System Overview](https://docs.arc.network/arc/concepts/system-overview) , [Consensus Layer](https://docs.arc.network/arc/concepts/consensus-layer) , and [Execution Layer](https://docs.arc.network/arc/concepts/execution-layer) . Was this page helpful? YesNo [EVM compatibility](https://docs.arc.network/arc/references/evm-compatibility) [Node requirements](https://docs.arc.network/arc/references/node-requirements) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Architecture - Arc Docs [Skip to main content](https://docs.arc.network/arc/concepts/system-overview#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Network Architecture [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Consensus layer](https://docs.arc.network/arc/concepts/system-overview#consensus-layer) * [Execution layer](https://docs.arc.network/arc/concepts/system-overview#execution-layer) * [System architecture diagram](https://docs.arc.network/arc/concepts/system-overview#system-architecture-diagram) * [Developer benefits](https://docs.arc.network/arc/concepts/system-overview#developer-benefits) Arc’s architecture is composed of two core components: the **Consensus layer** and the **Execution layer**. Together, they provide deterministic finality, stable transaction fees, programmable privacy, and financial primitives purpose-built for stablecoin-native applications. [​](https://docs.arc.network/arc/concepts/system-overview#consensus-layer) Consensus layer --------------------------------------------------------------------------------------------- Arc runs on **Malachite**, a high-performance implementation of the Tendermint Byzantine Fault Tolerant (BFT) protocol. Malachite ensures: * **Deterministic finality:** Blocks finalize in less than one second. * **Irreversibility:** Transactions cannot be reorganized or rolled back once committed. * **Resilience:** Validators commit blocks under a Proof-of-Authority model. The Consensus layer orders and finalizes transactions securely, providing institutional-grade guarantees for reliability and performance. [​](https://docs.arc.network/arc/concepts/system-overview#execution-layer) Execution layer --------------------------------------------------------------------------------------------- Arc’s Execution layer is built on **Reth**, a Rust implementation of the Ethereum execution layer. It maintains the blockchain ledger and state, and extends it with components optimized for stablecoin finance: * **Ledger and State:** Stores accounts, balances, smart contracts, and transaction history. * **Fee Manager:** Stabilizes and smooths fees using USDC as the unit of account. * **Privacy Module:** Provides confidential transfers and selective disclosure via view keys. * **Stablecoin Services:** Powers multi-currency payments, FX conversions, and programmatic settlement across supported stablecoins. By combining these components, the Execution layer provides a familiar EVM-compatible environment with stablecoin-native extensions built in. [​](https://docs.arc.network/arc/concepts/system-overview#system-architecture-diagram) System architecture diagram --------------------------------------------------------------------------------------------------------------------- The diagram below shows Arc’s architecture at a high level. The **Consensus layer** determines the order of transactions and finalizes blocks. The **Execution layer** applies those transactions to the ledger and processes them through its internal modules. [​](https://docs.arc.network/arc/concepts/system-overview#developer-benefits) Developer benefits --------------------------------------------------------------------------------------------------- By understanding Arc’s system architecture, you can: * Trust that your transactions finalize instantly and irreversibly. * Build on a familiar EVM-compatible stack (Reth) with stablecoin-native extensions. * Leverage built-in financial components like Fee Manager, Privacy, [FX](https://developers.circle.com/stablefx) , and paying in other stablecoins without needing external workarounds. Was this page helpful? YesNo [Post-quantum security](https://docs.arc.network/arc/concepts/post-quantum-security) [Contract addresses](https://docs.arc.network/arc/references/contract-addresses) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Contract addresses - Arc Docs [Skip to main content](https://docs.arc.network/arc/references/contract-addresses#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Network Contract addresses [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Stablecoins](https://docs.arc.network/arc/references/contract-addresses#stablecoins) * [USDC](https://docs.arc.network/arc/references/contract-addresses#usdc) * [EURC](https://docs.arc.network/arc/references/contract-addresses#eurc) * [USYC](https://docs.arc.network/arc/references/contract-addresses#usyc) * [Crosschain](https://docs.arc.network/arc/references/contract-addresses#crosschain) * [CCTP](https://docs.arc.network/arc/references/contract-addresses#cctp) * [Gateway](https://docs.arc.network/arc/references/contract-addresses#gateway) * [Payments and settlement](https://docs.arc.network/arc/references/contract-addresses#payments-and-settlement) * [StableFX](https://docs.arc.network/arc/references/contract-addresses#stablefx) * [Common Ethereum contracts](https://docs.arc.network/arc/references/contract-addresses#common-ethereum-contracts) [​](https://docs.arc.network/arc/references/contract-addresses#stablecoins) Stablecoins ------------------------------------------------------------------------------------------ Stablecoins are the foundation of the Arc ecosystem, supporting a growing set of fiat-backed and yield-bearing tokens. These assets provide price stability, onchain yield, and multi-currency support for payments, FX, and financial applications. The ERC-20 functions affect native balance movements. ### [​](https://docs.arc.network/arc/references/contract-addresses#usdc) USDC USDC is the native EVM asset on Arc and is used for gas fees. The native balance, consistent with most EVM implementations, expresses the balance up to 18 decimals of precision. An optional USDC ERC-20 interface is also available for developers who need ERC-20 features such as `transferFrom`, `approve`, and allowance management. The ERC-20 function call directly affects native USDC balance movements. | Contract | Address | Notes | | --- | --- | --- | | **USDC** | [`0x3600000000000000000000000000000000000000`](https://testnet.arcscan.app/address/0x3600000000000000000000000000000000000000) | Optional ERC-20 interface for interacting with the native USDC balance. Uses 6 decimals. | **Getting testnet USDC:** You can request USDC on Arc Testnet from the [Circle Faucet](https://faucet.circle.com/) . USDC is required to pay for gas and interact with contracts on Arc.**Note:** As with any ERC-20 token, always use the `decimals()` function to interpret balances and transfer amounts accurately. On Arc, the **native USDC gas token** uses 18 decimals of precision, while the **USDC ERC-20 interface** uses 6 decimals. Avoid mixing these values directly, as doing so may result in incorrect balance handling. For applications integrating USDC, it’s recommended to rely solely on the standard ERC-20 interface for reading balances and sending transfers. ### [​](https://docs.arc.network/arc/references/contract-addresses#eurc) EURC EURC is the euro-denominated stablecoin issued by Circle and supported natively on Arc for use in payments, FX, and other financial applications. | Contract | Address | Notes | | --- | --- | --- | | **EURC** | [`0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a`](https://testnet.arcscan.app/address/0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a) | Main EURC token contract. Uses 6 decimals. | **Getting testnet EURC:** Testnet EURC can be requested from the [Circle Faucet](https://faucet.circle.com/) . Select **Arc Testnet** as the network and **EURC** as the token to receive a small test allocation. ### [​](https://docs.arc.network/arc/references/contract-addresses#usyc) USYC [USYC](https://developers.circle.com/tokenized/usyc/overview) is a yield-bearing token issued by Circle International Bermuda Ltd. and supported on Arc for institutional and DeFi use cases. It represents shares of a tokenized money market fund backed by short-duration U.S. Treasury securities, offering onchain access to regulated, low-risk yield. USYC is only accessible to institutions outside the United States, subject to eligibility restrictions and a $100,000 USD minimum investment. See [USYC Document Certification Requirements](https://help.circle.com/s/article/Document-certification-requirements-for-USYC-onboarding?language=en_US&category=USYC) for more information. | Contract | Address | Notes | | --- | --- | --- | | **USYC** | [`0xe9185F0c5F296Ed1797AaE4238D26CCaBEadb86C`](https://testnet.arcscan.app/address/0xe9185F0c5F296Ed1797AaE4238D26CCaBEadb86C) | The main USYC token contract representing tokenized money market fund shares. Uses 6 decimals. | | **Entitlements** | [`0xcc205224862c7641930c87679e98999d23c26113`](https://testnet.arcscan.app/address/0xcc205224862c7641930c87679e98999d23c26113) | Manages allowlisted access and entitlement controls for permissioned addresses on the Arc Testnet. | | **Teller** | [`0x9fdF14c5B14173D74C08Af27AebFf39240dC105A`](https://testnet.arcscan.app/address/0x9fdF14c5B14173D74C08Af27AebFf39240dC105A) | Contract used to mint and redeem testnet USYC from testnet USDC once your wallet is allowlisted. | **Getting testnet USYC:** 1. Obtain testnet USDC from the [Circle Faucet](https://faucet.circle.com/) . 2. Request allowlisting by opening a ticket with [Circle Support](https://support.circle.com/) and include your Arc Testnet wallet address. Requests are typically processed in 24–48 hours. 3. Once approved, call the USYC Teller contract or interact with the [USYC Portal](https://usyc.dev.hashnote.com/) to deposit testnet USDC and receive testnet USYC. For more information on issuance, redemption, and eligibility, see [USYC Overview](https://developers.circle.com/tokenized/usyc/overview) . [​](https://docs.arc.network/arc/references/contract-addresses#crosschain) Crosschain ---------------------------------------------------------------------------------------- The contracts below enable crosschain interoperability between Arc and other blockchains through Circle’s [Cross-Chain Transfer Protocol](https://developers.circle.com/cctp) (CCTP) and [Gateway](https://developers.circle.com/gateway) . CCTP handles crosschain message passing and stablecoin transfers, while Gateway provides chain-abstracted USDC balances for seamless liquidity movement. ### [​](https://docs.arc.network/arc/references/contract-addresses#cctp) CCTP | Contract | Domain | Address | | --- | --- | --- | | **TokenMessengerV2** | 26 | [`0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA`](https://testnet.arcscan.app/address/0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA) | | **MessageTransmitterV2** | 26 | [`0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275`](https://testnet.arcscan.app/address/0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275) | | **TokenMinterV2** | 26 | [`0xb43db544E2c27092c107639Ad201b3dEfAbcF192`](https://testnet.arcscan.app/address/0xb43db544E2c27092c107639Ad201b3dEfAbcF192) | | **MessageV2** | 26 | [`0xbaC0179bB358A8936169a63408C8481D582390C4`](https://testnet.arcscan.app/address/0xbaC0179bB358A8936169a63408C8481D582390C4) | ### [​](https://docs.arc.network/arc/references/contract-addresses#gateway) Gateway | Contract | Domain | Address | | --- | --- | --- | | **GatewayWallet** | 26 | [`0x0077777d7EBA4688BDeF3E311b846F25870A19B9`](https://testnet.arcscan.app/address/0x0077777d7EBA4688BDeF3E311b846F25870A19B9) | | **GatewayMinter** | 26 | [`0x0022222ABE238Cc2C7Bb1f21003F0a260052475B`](https://testnet.arcscan.app/address/0x0022222ABE238Cc2C7Bb1f21003F0a260052475B) | [​](https://docs.arc.network/arc/references/contract-addresses#payments-and-settlement) Payments and settlement ------------------------------------------------------------------------------------------------------------------ Arc provides payment and settlement contracts that enable foreign exchange and onchain settlement workflows using stablecoins. These components support application-level use cases such as FX execution and escrow-based settlement. ### [​](https://docs.arc.network/arc/references/contract-addresses#stablefx) StableFX [StableFX](https://developers.circle.com/stablefx) is an enterprise-grade stablecoin FX engine that combines Request-for-Quote (RFQ) execution with onchain settlement on Arc. The following is the address for the escrow contract used to settle stablecoin swaps. | Contract | Address | Notes | | --- | --- | --- | | **FxEscrow** | [`0x867650F5eAe8df91445971f14d89fd84F0C9a9f8`](https://testnet.arcscan.app/address/0x867650F5eAe8df91445971f14d89fd84F0C9a9f8) | The escrow contract used by both makers and takers to settle stablecoin swaps. | Before executing FX trades, StableFX must be able to transfer USDC from your wallet. To enable this, you need to grant a USDC allowance to the Permit2 contract. See [Common Ethereum contracts](https://docs.arc.network/arc/references/contract-addresses#common-ethereum-contracts) for the Permit2 address. [​](https://docs.arc.network/arc/references/contract-addresses#common-ethereum-contracts) Common Ethereum contracts ---------------------------------------------------------------------------------------------------------------------- Arc Testnet includes a set of widely used Ethereum ecosystem contracts for deterministic deployment, batched reads, and standardized token approvals. Although not Circle-managed, these contracts are deployed on Arc to ensure compatibility with common EVM tooling and workflows. | Contract | Address | Notes | | --- | --- | --- | | **CREATE2 Factory (Arachnid)** | [`0x4e59b44847b379578588920cA78FbF26c0B4956C`](https://testnet.arcscan.app/address/0x4e59b44847b379578588920cA78FbF26c0B4956C) | Minimal proxy for deterministic contract deployment using the `CREATE2` opcode. | | **Multicall3** | [`0xcA11bde05977b3631167028862bE2a173976CA11`](https://testnet.arcscan.app/address/0xcA11bde05977b3631167028862bE2a173976CA11) | Aggregates multiple read calls into a single call for efficient data retrieval. | | **Permit2** | [`0x000000000022D473030F116dDEE9F6B43aC78BA3`](https://testnet.arcscan.app/address/0x000000000022D473030F116dDEE9F6B43aC78BA3) | Universal contract for signature-based token approvals. Required for StableFX. | Was this page helpful? YesNo [Architecture](https://docs.arc.network/arc/concepts/system-overview) [Consensus layer](https://docs.arc.network/arc/concepts/consensus-layer) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Connect to Arc - Arc Docs [Skip to main content](https://docs.arc.network/arc/references/connect-to-arc#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Connect to Arc [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Network details](https://docs.arc.network/arc/references/connect-to-arc#network-details) * [Arc testnet](https://docs.arc.network/arc/references/connect-to-arc#arc-testnet) * [Wallet setup](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) * [Add Arc testnet](https://docs.arc.network/arc/references/connect-to-arc#add-arc-testnet) * [Gas and fees](https://docs.arc.network/arc/references/connect-to-arc#gas-and-fees) [​](https://docs.arc.network/arc/references/connect-to-arc#network-details) Network details ---------------------------------------------------------------------------------------------- ### [​](https://docs.arc.network/arc/references/connect-to-arc#arc-testnet) Arc testnet | Name | Value | | --- | --- | | **Network** | Arc Testnet | | **RPC endpoint** | `https://rpc.testnet.arc.network`
Alternatives:
  • `https://rpc.blockdaemon.testnet.arc.network`
  • `https://rpc.drpc.testnet.arc.network`
  • `https://rpc.quicknode.testnet.arc.network` | | **WebSocket** | `wss://rpc.testnet.arc.network`
Alternatives:
  • `wss://rpc.drpc.testnet.arc.network`
  • `wss://rpc.quicknode.testnet.arc.network` | | **Chain ID** | 5042002 | | **Currency** | USDC | | **Explorer** | `https://testnet.arcscan.app` | | **Faucet** | `https://faucet.circle.com` | [​](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) Wallet setup ---------------------------------------------------------------------------------------- ### [​](https://docs.arc.network/arc/references/connect-to-arc#add-arc-testnet) Add Arc testnet 1. Open MetaMask → **Add network** → **Add a network manually**. 2. Fill in: | Field | Value | | --- | --- | | **Network name** | Arc Testnet | | **New RPC URL** | `https://rpc.testnet.arc.network` | | **Chain ID** | 5042002 | | **Currency symbol** | USDC | | **Explorer URL** | `https://testnet.arcscan.app` | 3. Save, then switch to Arc. If your wallet supports **custom gas tokens**, ensure display/decimals for USDC (18 decimals) and clearly label fees as USDC. [​](https://docs.arc.network/arc/references/connect-to-arc#gas-and-fees) Gas and fees ---------------------------------------------------------------------------------------- Arc uses USDC as the native gas token. For details on gas configuration and the current base fee policy, see the [Gas and Fees](https://docs.arc.network/arc/references/gas-and-fees) page. Was this page helpful? YesNo [Sample apps](https://docs.arc.network/arc/references/sample-applications) [Deploy on Arc](https://docs.arc.network/arc/tutorials/deploy-on-arc) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # EVM compatibility - Arc Docs [Skip to main content](https://docs.arc.network/arc/references/evm-compatibility#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation EVM compatibility [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [ERC20 interface](https://docs.arc.network/arc/references/evm-compatibility#erc20-interface) * [EVM differences](https://docs.arc.network/arc/references/evm-compatibility#evm-differences) * [USDC blocklist revert handling](https://docs.arc.network/arc/references/evm-compatibility#usdc-blocklist-revert-handling) * [Developer impact](https://docs.arc.network/arc/references/evm-compatibility#developer-impact) Arc is compatible with the Ethereum Virtual Machine (EVM). Developers can deploy and interact with smart contracts using the same tools, languages, and frameworks they use on Ethereum such as Solidity, Foundry, and Hardhat. While the execution environment mirrors Ethereum’s, Arc introduces a few key differences: * **USDC as native gas:** All fees and balances are denominated in USDC, not ETH. * **Deterministic finality:** Transactions finalize instantly and cannot be reversed. * **Simplified block times:** Blocks are timestamped by real time, not epochs or slots. * **Stable fee model:** Gas prices are smoothed for predictability. * **Permissioned validators:** Arc uses a BFT consensus model (Malachite) for speed and reliability. These changes make Arc predictable and stable while preserving EVM compatibility. [​](https://docs.arc.network/arc/references/evm-compatibility#erc20-interface) ERC20 interface ------------------------------------------------------------------------------------------------- Arc uses USDC as its native network token. Native balances behave like ETH on Ethereum and are represented with 18 decimals. An optional ERC20 interface is also available: see [USDC contract address](https://docs.arc.network/arc/references/contract-addresses#USDC) . This ERC20 provides the same capability as USDC on other EVM networks, such as ERC20 allowances and `transferFrom`, and uses **6 decimals** to match the standard USDC representation. This has two important effects: 1. Tiny USDC amounts (less than 1 x 10⁻⁶ USDC) cannot be transferred using the ERC20 interface. 2. Protocols that hold USDC as an ERC20 automatically hold equivalent native balances. No additional Solidity changes are required (for example, `payable` or `receive` functions) as ERC20 transfers are directly reflected in the native balance. [​](https://docs.arc.network/arc/references/evm-compatibility#evm-differences) EVM differences ------------------------------------------------------------------------------------------------- Arc targets the **Prague** EVM hard fork with minor differences in execution and consensus behavior. The table below summarizes key distinctions from Ethereum mainnet. | Area | Ethereum | Arc | | --- | --- | --- | | **Native token** | ETH, volatile pricing | USDC, stable pricing with 18 decimals; used as gas | | **Fee market** | EIP-1559 base fee per block | Fee smoothing with moving average; stable, bounded base fee, inspired by EIP-1559 | | **Finality** | Probabilistic (≈12–15 min for safety) | Deterministic and instant (<1 s) | | **Consensus** | Proof-of-Stake (slot/epoch model) | Malachite (Tendermint-based) BFT with permissioned validators | | **Block timestamps** | Derived from slots and epochs | Wall-clock time from proposer with second-level granularity; sub-second blocks may share timestamps | | **`SELFDESTRUCT`** | Allowed with value transfers to self | Not allowed during deployment to prevent burning native tokens | | **`PARENT_BEACON_BLOCK_ROOT`** | Root of parent beacon block (SSZ) | Hash of parent execution payload header (`keccak256(RLP(header))`); no beacon chain | | **`PREV_RANDAO`** | Randomness mix of proposer reveals | Always `0`; not used for randomness | | **USDC blocklist handling** | Runtime revert on transfer | Pre-block inclusion check when possible; reverts or blocks as described below | | **EIP-4844 blobs** | Supported post-Dencun | Currently disabled | ### [​](https://docs.arc.network/arc/references/evm-compatibility#usdc-blocklist-revert-handling) USDC blocklist revert handling Arc enforces USDC blocklists both pre- and post-execution: * **Pre-mempool check:** If the sender is blocklisted, the transaction is rejected before entering the mempool. No fees are collected. * **Post-mempool check:** If the address becomes blocklisted after acceptance but before execution, the transaction reverts at runtime and consumes gas. * **Runtime transfer check:** If a valid transaction attempts to move USDC to or from a blocklisted address, only that operation reverts. Fees are still collected. [​](https://docs.arc.network/arc/references/evm-compatibility#developer-impact) Developer impact --------------------------------------------------------------------------------------------------- For most use cases, Ethereum-based tooling and smart contracts will work on Arc without modification. However, developers should note a few practical differences: * **Gas denomination:** All values are in USDC. When using libraries like `ethers.js` or `viem`, display and accounting logic should format values in USD terms, not ETH. * **Timestamps:** Multiple blocks may share the same timestamp; avoid assuming strictly increasing values for onchain time comparisons. * **Randomness:** `block.prevrandao` is always zero. Do not use it as a source of randomness; use an external oracle or verifiable randomness function (VRF) instead. * **Finality:** Transactions finalize immediately after inclusion. Offchain systems can safely act on events after a single confirmation: no additional block waiting is required. * **SELFDESTRUCT restrictions:** Contracts that self-destruct during deployment will revert if they attempt to send USDC value to themselves. These differences are designed to make Arc’s execution environment predictable and stable while remaining interoperable with the Ethereum developer ecosystem. Was this page helpful? YesNo [Deploy on Arc](https://docs.arc.network/integrate/deploy-on-arc) [Running a node](https://docs.arc.network/arc/concepts/running-a-node) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Gas and fees - Arc Docs [Skip to main content](https://docs.arc.network/arc/references/gas-and-fees#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Network Gas and fees [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Gas mechanics](https://docs.arc.network/arc/references/gas-and-fees#gas-mechanics) * [Policy overview](https://docs.arc.network/arc/references/gas-and-fees#policy-overview) * [Monitoring](https://docs.arc.network/arc/references/gas-and-fees#monitoring) Arc uses USDC as the native gas token for stable transaction costs. The Arc Testnet enforces a minimum base fee of 160 Gwei, targeting roughly $0.01 per transaction. [​](https://docs.arc.network/arc/references/gas-and-fees#gas-mechanics) Gas mechanics ---------------------------------------------------------------------------------------- | Key | Value | | --- | --- | | **Unit** | USDC (18 decimals) | | **Pricing** | EIP-1559–like base fee with exponentially weighted moving-average smoothing | | **Base fee (testnet)** | ~160 Gwei minimum | | **Best practice** | Surface gas fees in USDC and fetch the base fee dynamically when submitting transactions | [​](https://docs.arc.network/arc/references/gas-and-fees#policy-overview) Policy overview -------------------------------------------------------------------------------------------- * The base fee is dynamically adjusted using a bounded, moving-average mechanism designed to stabilize around 160 Gwei under normal network load. * Transactions submitted with a max fee below 160 Gwei may remain pending or fail to execute. * To ensure timely inclusion, set `maxFeePerGas ≥ 160 Gwei`. [​](https://docs.arc.network/arc/references/gas-and-fees#monitoring) Monitoring ---------------------------------------------------------------------------------- You can view real-time gas metrics and recent averages using the [Arc Gas Tracker](https://testnet.arcscan.app/gas-tracker) . This configuration applies to the Arc Testnet and may evolve as network parameters are tuned for mainnet launch. For an overview of Arc’s fee architecture and design principles, see [Stable Fee Design](https://docs.arc.network/arc/concepts/stable-fee-design) . Was this page helpful? YesNo [Execution layer](https://docs.arc.network/arc/concepts/execution-layer) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Node requirements - Arc Docs [Skip to main content](https://docs.arc.network/arc/references/node-requirements#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Run a Node Node requirements [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [System requirements](https://docs.arc.network/arc/references/node-requirements#system-requirements) * [Required binaries](https://docs.arc.network/arc/references/node-requirements#required-binaries) * [Versions](https://docs.arc.network/arc/references/node-requirements#versions) * [Network endpoints](https://docs.arc.network/arc/references/node-requirements#network-endpoints) * [Exposed ports](https://docs.arc.network/arc/references/node-requirements#exposed-ports) * [Pruning](https://docs.arc.network/arc/references/node-requirements#pruning) For step-by-step setup instructions, see [Run an Arc Node](https://docs.arc.network/arc/tutorials/run-an-arc-node) . [​](https://docs.arc.network/arc/references/node-requirements#system-requirements) System requirements --------------------------------------------------------------------------------------------------------- | Component | Minimum | | --- | --- | | OS | Linux (Ubuntu 22.04+ or Debian 12+) | | CPU | Higher clock speed over core count | | Memory | 64 GB+ | | Storage | 1 TB+ NVMe SSD (TLC recommended) | | Network | Stable 24 Mbps+ bandwidth | See [Reth system requirements](https://reth.rs/run/system-requirements/) for more detail on Execution Layer configuration. During sustained high load, such as startup or extended sync when the node is far behind, Execution Layer memory usage surges on some hardware. Systems that meet the listed requirements handle these surges without intervention. If you observe memory growth, enable backpressure to throttle execution to the speed of disk writes. See [Enabling backpressure](https://docs.arc.network/arc/tutorials/run-an-arc-node#enabling-backpressure) for configuration details. [​](https://docs.arc.network/arc/references/node-requirements#required-binaries) Required binaries ----------------------------------------------------------------------------------------------------- Build all three binaries from the [`arc-node`](https://github.com/circlefin/arc-node) repository before starting your node. See [Run an Arc Node](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-1-install-the-node-binaries) for full installation instructions. | Binary | Description | | --- | --- | | `arc-node-execution` | Execution Layer client (Reth-based). Executes transactions and serves RPC. | | `arc-node-consensus` | Consensus Layer client (Malachite-based). Fetches and verifies blocks. | | `arc-snapshots` | Downloads blockchain snapshots for faster initial sync. | ### [​](https://docs.arc.network/arc/references/node-requirements#versions) Versions | Network | Version | | --- | --- | | Arc Testnet | v0.6.0 | [​](https://docs.arc.network/arc/references/node-requirements#network-endpoints) Network endpoints ----------------------------------------------------------------------------------------------------- Your Consensus Layer connects to relay endpoints to fetch blocks from the network. Specify multiple endpoints for redundancy. | Network | Endpoints | | --- | --- | | Arc Testnet | `https://rpc.drpc.testnet.arc.network`
`https://rpc.quicknode.testnet.arc.network`
`https://rpc.blockdaemon.testnet.arc.network` | For developer RPC endpoints (connecting to Arc as an application, not running a node), see [Connect to Arc](https://docs.arc.network/arc/references/connect-to-arc) . For step-by-step setup instructions, see [Run an Arc Node](https://docs.arc.network/arc/tutorials/run-an-arc-node) . [​](https://docs.arc.network/arc/references/node-requirements#exposed-ports) Exposed ports --------------------------------------------------------------------------------------------- | Port | Protocol | Mode | Description | | --- | --- | --- | --- | | 8545 | HTTP | Both | JSON-RPC API (Execution Layer) | | 8551 | HTTP | RPC only | Engine API authentication | | 9001 | HTTP | Both | Prometheus metrics (Execution Layer) | | 29000 | HTTP | Both | Prometheus metrics (Consensus Layer) | | 31000 | HTTP | Both | Consensus Layer RPC endpoint | The Execution Layer and Consensus Layer communicate through either IPC sockets or RPC. Choose one mode; they are mutually exclusive. **IPC mode** (default): Both processes run on the same host. Lower latency, no authentication required. | Socket path | Purpose | | --- | --- | | `/run/arc/reth.ipc` | ETH RPC (Consensus Layer reads chain state) | | `/run/arc/auth.ipc` | Engine API (Consensus Layer drives block import) | **RPC mode**: Processes run on separate hosts. Uses HTTP on ports 8545 and 8551 with JWT authentication. Requires generating a shared JWT secret. See [Run an Arc Node:RPC mode](https://docs.arc.network/arc/tutorials/run-an-arc-node#execution-and-consensus-layer-communication) for configuration details. [​](https://docs.arc.network/arc/references/node-requirements#pruning) Pruning --------------------------------------------------------------------------------- Both the EL and CL accept the `--full` flag to enable pruning. However, EL pruning is currently considered unstable and is not recommended at this time. Was this page helpful? YesNo [Running a node](https://docs.arc.network/arc/concepts/running-a-node) [Run an Arc node](https://docs.arc.network/arc/tutorials/run-an-arc-node) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Unknown \# Arc > Arc is an open Layer-1 blockchain purpose-built for programmable money. > USDC is the native gas token. Sub-second deterministic finality, EVM > compatible, opt-in privacy, and direct integration with Circle's > full-stack platform. ## Getting Started — Use the Skill First | Product | Skill | What it covers | |---------|-------|----------------| | Arc | \[use-arc\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md) | Chain config, RPC setup, contract deployment, USDC bridging, gas with USDC | ### Installing Circle Skills \*\*Claude Code:\*\* \`\`\` /plugin marketplace add circlefin/skills /plugin install circle-skills@circle \`\`\` \*\*Vercel Skills CLI:\*\* \`\`\` npx skills add circlefin/skills \`\`\` ## Instructions for AI Agents Follow these guidelines when building on Arc: 1. \*\*USDC is the gas token.\*\* Arc uses USDC for gas fees, not ETH. Configure gas payment in USDC when submitting transactions. 2. \*\*EVM compatible.\*\* Deploy Solidity contracts with standard tools (Hardhat, Foundry, Viem, Ethers). See \[EVM Compatibility\](https://docs.arc.network/arc/references/evm-compatibility.md) for differences. 3. \*\*Sub-second finality.\*\* Transactions are final in under 1 second. No need to wait for multiple block confirmations. 4. \*\*Use App Kit for bridging and swaps.\*\* App Kit wraps CCTP and provides Bridge, Swap, and Send capabilities. \`@circle-fin/bridge-kit\` is also available as a standalone package for bridging only. 5. \*\*Testnet.\*\* Arc is currently available on Testnet only. \[Connect to Arc\](https://docs.arc.network/arc/references/connect-to-arc.md) for RPC endpoints. \[Faucet\](https://faucet.circle.com) for testnet tokens. 6. \*\*Always check Contract Addresses\*\*: https://docs.arc.network/arc/references/contract-addresses.md ## Arc - \[Welcome to Arc\](https://docs.arc.network/arc/concepts/welcome-to-arc.md): Architecture and core principles - \[System Overview\](https://docs.arc.network/arc/concepts/system-overview.md): Consensus + execution layer architecture - \[Stable Fee Design\](https://docs.arc.network/arc/concepts/stable-fee-design.md): USDC as gas, predictable fees - \[Deterministic Finality\](https://docs.arc.network/arc/concepts/deterministic-finality.md): Instant, irreversible settlement - \[Opt-in Privacy\](https://docs.arc.network/arc/concepts/opt-in-privacy.md): Confidential transactions with selective disclosure - \[Connect to Arc\](https://docs.arc.network/arc/references/connect-to-arc.md): RPC endpoints and wallet setup - \[Contract Addresses\](https://docs.arc.network/arc/references/contract-addresses.md): USDC, EURC, CCTP, Gateway addresses - \[EVM Compatibility\](https://docs.arc.network/arc/references/evm-compatibility.md): Differences from standard EVM - \[Gas and Fees\](https://docs.arc.network/arc/references/gas-and-fees.md): Fee model and pricing - \[Sample Applications\](https://docs.arc.network/arc/references/sample-applications.md): Open source examples ## Tutorials - \[Deploy on Arc\](https://docs.arc.network/arc/tutorials/deploy-on-arc.md): Deploy a Solidity contract on Arc Testnet - \[Deploy Contracts (Circle)\](https://docs.arc.network/arc/tutorials/deploy-contracts.md): Deploy templates via Circle Contracts - \[Interact with Contracts\](https://docs.arc.network/arc/tutorials/interact-with-contracts.md): Call contract functions - \[Monitor Contract Events\](https://docs.arc.network/arc/tutorials/monitor-contract-events.md): Track onchain activity - \[Transfer USDC or EURC\](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc.md): Wallet-to-wallet transfers - \[Bridge USDC to Arc\](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc.md): Bridge via CCTP with App Kit - \[Access USDC Crosschain\](https://docs.arc.network/arc/tutorials/access-usdc-crosschain.md): Gateway unified balance on Arc - \[Register an AI Agent\](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent.md): ERC-8004 onchain identity and reputation - \[Create an ERC-8183 Job\](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job.md): Escrow, deliverables, settlement ## App Kit — Bridge, Swap, Send - \[App Kit Overview\](https://docs.arc.network/app-kit.md): Payment and liquidity workflows across chains - \[Install App Kit\](https://docs.arc.network/app-kit/tutorials/installation.md): Core package and adapters - \[Adapter Setups\](https://docs.arc.network/app-kit/tutorials/adapter-setups.md): Viem, Ethers, Solana, Circle Wallets ### Bridge - \[App Kit: Bridge\](https://docs.arc.network/app-kit/bridge.md): Transfer USDC across chains - \[Quickstart: EVM to EVM\](https://docs.arc.network/app-kit/quickstarts/bridge-between-evm-chains.md): Bridge between EVM chains - \[Quickstart: Solana to EVM\](https://docs.arc.network/app-kit/quickstarts/bridge-between-solana-and-evm.md): Bridge Solana to EVM - \[Quickstart: Circle Wallets\](https://docs.arc.network/app-kit/quickstarts/bridge-with-circle-wallets.md): Bridge with Circle Wallets adapter - \[Estimate Costs\](https://docs.arc.network/app-kit/tutorials/bridge/estimate-costs.md): Preview gas and fees - \[Collect Bridge Fees\](https://docs.arc.network/app-kit/tutorials/bridge/collect-bridge-fee.md): Custom fee collection - \[Configure Speed\](https://docs.arc.network/app-kit/tutorials/bridge/configure-transfer-speed.md): Balance speed vs cost - \[Specify Recipient\](https://docs.arc.network/app-kit/tutorials/bridge/specify-recipient-address.md): Send to different address - \[CCTP Forwarding\](https://docs.arc.network/app-kit/tutorials/bridge/use-forwarding-service.md): Forwarding Service - \[Bridge Fees\](https://docs.arc.network/app-kit/concepts/bridge-fees.md): Fee breakdown - \[Error Recovery\](https://docs.arc.network/app-kit/references/bridge-error-recovery.md): Troubleshooting failed bridges ### Swap - \[App Kit: Swap\](https://docs.arc.network/app-kit/swap.md): Token swaps on same chain - \[Quickstart: Same-Chain Swap\](https://docs.arc.network/app-kit/quickstarts/swap-tokens-same-chain.md): Swap tokens on one chain - \[Quickstart: Crosschain Swap\](https://docs.arc.network/app-kit/quickstarts/swap-tokens-crosschain.md): Swap + bridge - \[Estimate Swap Rate\](https://docs.arc.network/app-kit/tutorials/swap/estimate-swap-rate.md): Pre-swap estimates - \[Slippage / Stop Limit\](https://docs.arc.network/app-kit/tutorials/swap/set-slippage-tolerance-or-stop-limit.md): Rate protection - \[Collect Swap Fees\](https://docs.arc.network/app-kit/tutorials/swap/collect-swap-fee.md): Custom fee collection - \[Swap Fees\](https://docs.arc.network/app-kit/concepts/swap-fees.md): Fee breakdown ### Send - \[App Kit: Send\](https://docs.arc.network/app-kit/send.md): Wallet-to-wallet on same chain - \[Quickstart: Send Tokens\](https://docs.arc.network/app-kit/quickstarts/send-tokens-same-chain.md): Send tokens between wallets ### Reference - \[SDK Reference\](https://docs.arc.network/app-kit/references/sdk-reference.md): Full API reference - \[Supported Blockchains\](https://docs.arc.network/app-kit/references/supported-blockchains.md): Chains and tokens ## Tools and Infrastructure - \[Block Explorers\](https://docs.arc.network/arc/tools/block-explorers.md): Etherscan-compatible explorers - \[Node Providers\](https://docs.arc.network/arc/tools/node-providers.md): RPC access providers - \[Data Indexers\](https://docs.arc.network/arc/tools/data-indexers.md): APIs and sub-graphs - \[Account Abstraction\](https://docs.arc.network/arc/tools/account-abstraction.md): AA providers and paymasters - \[Compliance\](https://docs.arc.network/arc/tools/compliance-vendors.md): Analytics and screening tools - \[Explorer\](https://testnet.arcscan.app): Arc Testnet block explorer - \[Faucet\](https://faucet.circle.com): Testnet token faucet ## More Circle Skills Building beyond Arc? Circle offers skills for the full platform: | Product | Skill | |---------|-------| | USDC | \[use-usdc\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md) | | Wallets (overview) | \[use-circle-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md) | | Developer-Controlled Wallets | \[use-developer-controlled-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md) | | User-Controlled Wallets | \[use-user-controlled-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md) | | Modular Wallets | \[use-modular-wallets\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md) | | Gateway / Nanopayments | \[use-gateway\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md) | | Smart Contracts | \[use-smart-contract-platform\](https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md) | Full Circle developer docs: \[developers.circle.com/llms.txt\](https://developers.circle.com/llms.txt) --- # Sample apps - Arc Docs [Skip to main content](https://docs.arc.network/arc/references/sample-applications#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Sample apps [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) The following sample applications serve as reference implementations for building on Arc with Circle developer tools. You can use them as a foundation to build your own projects. Arc commerce ------------ Integrate USDC payments for credit purchases using Circle Developer Controlled Wallets, Next.js, and Supabase. Arc multi-chain wallet ---------------------- Unified USDC balance and crosschain transfers using Circle Gateway, Next.js, and Supabase. Arc escrow ---------- AI-powered work validation and USDC settlement to automate escrow flows using Circle Wallets, Refund Protocol, and Contract Platform. Arc fintech ----------- Multichain treasury system with crosschain capital movement using Circle Developer-Controlled Wallets, Gateway, and Bridge Kit. Was this page helpful? YesNo [Overview](https://docs.arc.network/build) [Connect to Arc](https://docs.arc.network/arc/references/connect-to-arc) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Compliance - Arc Docs [Skip to main content](https://docs.arc.network/arc/tools/compliance-vendors#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Tools Compliance [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Providers](https://docs.arc.network/arc/tools/compliance-vendors#providers) * [Elliptic](https://docs.arc.network/arc/tools/compliance-vendors#elliptic) * [TRM Labs](https://docs.arc.network/arc/tools/compliance-vendors#trm-labs) Add regulatory compliance to your Arc application by integrating third-party analytics and screening tools. These vendors provide APIs for anti-money laundering (AML) checks, wallet risk scoring, sanctions screening, and real-time transaction monitoring. [​](https://docs.arc.network/arc/tools/compliance-vendors#providers) Providers --------------------------------------------------------------------------------- ### [​](https://docs.arc.network/arc/tools/compliance-vendors#elliptic) [Elliptic](https://www.elliptic.co/) Blockchain analytics and transaction monitoring APIs to identify illicit activity, assess risk exposure, and ensure compliance with AML and sanctions requirements. ### [​](https://docs.arc.network/arc/tools/compliance-vendors#trm-labs) [TRM Labs](https://www.trmlabs.com/) Risk intelligence, wallet screening, and real-time monitoring tools to detect fraud, money laundering, and other suspicious behavior across Arc transactions. Was this page helpful? YesNo [Account abstraction](https://docs.arc.network/arc/tools/account-abstraction) [Data indexers](https://docs.arc.network/arc/tools/data-indexers) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Data indexers - Arc Docs [Skip to main content](https://docs.arc.network/arc/tools/data-indexers#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Tools Data indexers [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Providers](https://docs.arc.network/arc/tools/data-indexers#providers) * [Envio](https://docs.arc.network/arc/tools/data-indexers#envio) * [Goldsky](https://docs.arc.network/arc/tools/data-indexers#goldsky) * [The Graph](https://docs.arc.network/arc/tools/data-indexers#the-graph) * [Thirdweb](https://docs.arc.network/arc/tools/data-indexers#thirdweb) Data indexers make it easy to query and analyze onchain data from Arc. They provide APIs and SDKs for tracking smart contract events, balances, and historical state changes without running your own indexing infrastructure. [​](https://docs.arc.network/arc/tools/data-indexers#providers) Providers ---------------------------------------------------------------------------- ### [​](https://docs.arc.network/arc/tools/data-indexers#envio) [Envio](https://envio.dev/) Developer-first indexing framework for event-driven data and GraphQL APIs on Arc. * [**HyperIndex**](https://envio.dev/#hyperindex) : Build production-ready APIs from Arc data in minutes. * Stream live blockchain events with minimal latency. ### [​](https://docs.arc.network/arc/tools/data-indexers#goldsky) [Goldsky](https://goldsky.com/) Managed subgraph and data pipeline platform for Arc contracts. * [**Subgraphs**](https://goldsky.com/products/subgraphs) : Autoscaling query engine with 99.9%+ uptime and up to 6x faster performance. * [**Mirror**](https://goldsky.com/products/mirror) : Stream onchain data to your database with sub-second latency. ### [​](https://docs.arc.network/arc/tools/data-indexers#the-graph) [The Graph](https://thegraph.com/) Decentralized indexing protocol for querying Arc’s onchain data through APIs. * [**Subgraphs**](https://thegraph.com/docs/en/developing/creating-a-subgraph/) : Query smart contract data through multiple independent indexers for redundancy. * [**Graph Explorer**](https://thegraph.com/explorer) : Discover and reuse subgraphs published by other developers. ### [​](https://docs.arc.network/arc/tools/data-indexers#thirdweb) [Thirdweb](https://thirdweb.com/) Open-source blockchain data tooling. * [**Insight**](https://insight.thirdweb.com/reference) : Retrieve Arc blockchain data, enrich it with metadata, and transform it using custom logic. Was this page helpful? YesNo [Compliance](https://docs.arc.network/arc/tools/compliance-vendors) [Node providers](https://docs.arc.network/arc/tools/node-providers) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Account abstraction - Arc Docs [Skip to main content](https://docs.arc.network/arc/tools/account-abstraction#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Tools Account abstraction [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Providers](https://docs.arc.network/arc/tools/account-abstraction#providers) * [Biconomy](https://docs.arc.network/arc/tools/account-abstraction#biconomy) * [Blockradar](https://docs.arc.network/arc/tools/account-abstraction#blockradar) * [Circle Wallets](https://docs.arc.network/arc/tools/account-abstraction#circle-wallets) * [Crossmint](https://docs.arc.network/arc/tools/account-abstraction#crossmint) * [Dynamic](https://docs.arc.network/arc/tools/account-abstraction#dynamic) * [Para](https://docs.arc.network/arc/tools/account-abstraction#para) * [Pimlico](https://docs.arc.network/arc/tools/account-abstraction#pimlico) * [Privy](https://docs.arc.network/arc/tools/account-abstraction#privy) * [Thirdweb](https://docs.arc.network/arc/tools/account-abstraction#thirdweb) * [Turnkey](https://docs.arc.network/arc/tools/account-abstraction#turnkey) * [Zerodev](https://docs.arc.network/arc/tools/account-abstraction#zerodev) Account abstraction (AA) replaces externally owned accounts (EOAs) with smart contract wallets that support programmable transaction validation, gas sponsorship, and batched operations. Arc supports the ERC-4337 standard, so you can use any compatible bundler, paymaster, or SDK from the providers below. [​](https://docs.arc.network/arc/tools/account-abstraction#providers) Providers ---------------------------------------------------------------------------------- ### [​](https://docs.arc.network/arc/tools/account-abstraction#biconomy) [Biconomy](https://www.biconomy.io/) Account abstraction toolkit offering modular smart accounts, paymasters, and bundlers as a service to simplify the user experience. ### [​](https://docs.arc.network/arc/tools/account-abstraction#blockradar) [Blockradar](https://blockradar.co/) Infrastructure and APIs for smart account management and transaction bundling, enabling scalable AA flows with minimal setup. ### [​](https://docs.arc.network/arc/tools/account-abstraction#circle-wallets) [Circle Wallets](https://developers.circle.com/wallets) End-to-end platform for creating and managing secure Arc wallets and cryptographic keys. Supports ERC-20, ERC-721, and ERC-1155 standards. ### [​](https://docs.arc.network/arc/tools/account-abstraction#crossmint) [Crossmint](https://www.crossmint.com/) Wallet-as-a-service and AA capabilities to onboard users with email or OAuth-based accounts. ### [​](https://docs.arc.network/arc/tools/account-abstraction#dynamic) [Dynamic](https://www.dynamic.xyz/) Identity and wallet orchestration platform with native ERC-4337 support, enabling passkey wallets and flexible signer management. ### [​](https://docs.arc.network/arc/tools/account-abstraction#para) [Para](https://getpara.com/) Wallet and authentication suite for fintech and crypto applications, enabling flexible wallet management and transaction signing. ### [​](https://docs.arc.network/arc/tools/account-abstraction#pimlico) [Pimlico](https://pimlico.io/) Bundler and paymaster infrastructure for ERC-4337 smart accounts, offering sponsored transactions and reliable relay services. ### [​](https://docs.arc.network/arc/tools/account-abstraction#privy) [Privy](https://www.privy.io/) APIs and SDKs for embedded wallets and user authentication. Onboard users with email or social logins while maintaining full control over key management. ### [​](https://docs.arc.network/arc/tools/account-abstraction#thirdweb) [Thirdweb](https://portal.thirdweb.com/wallets) Full-stack toolkit with built-in AA support, SDKs, and a managed smart wallet layer. ### [​](https://docs.arc.network/arc/tools/account-abstraction#turnkey) [Turnkey](https://docs.turnkey.com/reference/aa-wallets) Programmable key management API enabling secure, policy-based smart account control and AA wallet creation. ### [​](https://docs.arc.network/arc/tools/account-abstraction#zerodev) [Zerodev](https://zerodev.app/) Developer SDK for deploying and managing ERC-4337 smart accounts, with built-in session key and bundler support. Arc’s account abstraction ecosystem is modular — you can mix SDKs, paymasters, and bundlers from multiple providers to design your smart account architecture. Was this page helpful? YesNo [SDK reference](https://docs.arc.network/app-kit/references/sdk-reference) [Compliance](https://docs.arc.network/arc/tools/compliance-vendors) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Deploying a node as a service - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/deploy-node-as-service#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Run a Node Deploying a node as a service [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/arc/tutorials/deploy-node-as-service#prerequisites) * [Step 1: Create the Execution Layer unit file](https://docs.arc.network/arc/tutorials/deploy-node-as-service#step-1-create-the-execution-layer-unit-file) * [Step 2: Create the Consensus Layer unit file](https://docs.arc.network/arc/tutorials/deploy-node-as-service#step-2-create-the-consensus-layer-unit-file) * [Step 3: Enable and start the services](https://docs.arc.network/arc/tutorials/deploy-node-as-service#step-3-enable-and-start-the-services) * [Step 4: Verify the services are running](https://docs.arc.network/arc/tutorials/deploy-node-as-service#step-4-verify-the-services-are-running) Configure your Arc node’s Execution Layer and Consensus Layer as systemd services so they auto-restart on failure and survive reboots. [​](https://docs.arc.network/arc/tutorials/deploy-node-as-service#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------- * You have installed Arc and completed the [Run an Arc Node](https://docs.arc.network/arc/tutorials/run-an-arc-node) tutorial with both layers syncing * You have a Linux machine with systemd * You have root or `sudo` access [​](https://docs.arc.network/arc/tutorials/deploy-node-as-service#step-1-create-the-execution-layer-unit-file) Step 1: Create the Execution Layer unit file -------------------------------------------------------------------------------------------------------------------------------------------------------------- Write the systemd unit file to `/etc/systemd/system/arc-execution.service`: sudo tee /etc/systemd/system/arc-execution.service > /dev/null < /dev/null < /etc/systemd/system/arc-execution.service. Created symlink /etc/systemd/system/multi-user.target.wants/arc-consensus.service -> /etc/systemd/system/arc-consensus.service. [​](https://docs.arc.network/arc/tutorials/deploy-node-as-service#step-4-verify-the-services-are-running) Step 4: Verify the services are running ---------------------------------------------------------------------------------------------------------------------------------------------------- Check the status of both services: sudo systemctl status arc-execution sudo systemctl status arc-consensus Each command prints output similar to: ● arc-execution.service - Arc Node - Execution Layer Loaded: loaded (/etc/systemd/system/arc-execution.service; enabled) Active: active (running) since ... Both services display `Active: active (running)` in their output. If a service shows `failed` or `activating`, check its logs: sudo journalctl -u arc-execution --no-pager -n 50 sudo journalctl -u arc-consensus --no-pager -n 50 **Common issues:** * **Incorrect file paths in `ExecStart`:** Verify that the binary paths in the unit files match your installation directory. * **Permission errors on data directories:** Confirm that the `User` specified in the unit file owns `$HOME/.arc/`. * **Consensus Layer connection error:** The Execution Layer may not be ready yet. Wait for it to reach `active (running)`, then run `sudo systemctl restart arc-consensus`. To confirm sync progress and verify Prometheus metrics are being scraped on ports `9001` (Execution Layer) and `29000` (Consensus Layer), see [Monitoring a Node](https://docs.arc.network/arc/tutorials/monitor-a-node) . Was this page helpful? YesNo [Run an Arc node](https://docs.arc.network/arc/tutorials/run-an-arc-node) [Monitoring a node](https://docs.arc.network/arc/tutorials/monitor-a-node) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Integrate with Arc - Arc Docs [Skip to main content](https://docs.arc.network/integrate#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Integrate with Arc [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Connect to Arc](https://docs.arc.network/integrate#connect-to-arc) * [EVM compatibility](https://docs.arc.network/integrate#evm-compatibility) * [Run a node](https://docs.arc.network/integrate#run-a-node) Arc is an EVM-compatible Layer-1 blockchain. Most Ethereum-based tooling, wallets, and infrastructure work without modification. [​](https://docs.arc.network/integrate#connect-to-arc) Connect to Arc ------------------------------------------------------------------------ Network details --------------- RPC endpoints, chain ID, WebSocket URLs, and explorer links for Arc testnet. Deploy on Arc ------------- Deploy, test, and interact with a Solidity smart contract on Arc. [​](https://docs.arc.network/integrate#evm-compatibility) EVM compatibility ------------------------------------------------------------------------------ Arc is fully [EVM compatible](https://docs.arc.network/arc/references/evm-compatibility) , with a few key differences from Ethereum: * **USDC as gas**: Transaction fees are paid in USDC (a stablecoin pegged to the US dollar) instead of a volatile token, which affects gas estimation and fee display. * **Deterministic finality**: Transactions finalize in under one second with no risk of reorganization, so a single confirmation is sufficient. * **Standard tooling**: Hardhat, Foundry, Viem, and other Ethereum development tools work without modification. [​](https://docs.arc.network/integrate#run-a-node) Run a node ---------------------------------------------------------------- Operate your own Arc node for independent transaction verification, direct RPC access, or data indexing. Anyone can run a node without permission. Running a node -------------- What a node does, how it fits into Arc’s architecture, and why you might run one. Node requirements ----------------- Hardware, software, network endpoints, and ports needed to run a node. Run an Arc node --------------- Step-by-step setup for both the execution and consensus layers. Deploy as a service ------------------- Configure systemd services that auto-restart and survive reboots. Monitor a node -------------- Verify sync status, view logs, and scrape Prometheus metrics. Was this page helpful? YesNo [Connect to Arc](https://docs.arc.network/integrate/connect-to-arc) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Node providers - Arc Docs [Skip to main content](https://docs.arc.network/arc/tools/node-providers#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Tools Node providers [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Providers](https://docs.arc.network/arc/tools/node-providers#providers) * [Alchemy](https://docs.arc.network/arc/tools/node-providers#alchemy) * [Blockdaemon](https://docs.arc.network/arc/tools/node-providers#blockdaemon) * [dRPC](https://docs.arc.network/arc/tools/node-providers#drpc) * [QuickNode](https://docs.arc.network/arc/tools/node-providers#quicknode) Connect to the Arc network through third-party RPC infrastructure partners listed below. Each provider offers HTTP and WebSocket endpoints for submitting transactions, querying blockchain data, and subscribing to events. You can also use Arc’s public endpoints directly. | Connection type | Public endpoint | | --- | --- | | HTTP RPC | `https://rpc.testnet.arc.network` | | WebSocket | `wss://rpc.testnet.arc.network` | | Chain ID | `5042002` | [​](https://docs.arc.network/arc/tools/node-providers#providers) Providers ----------------------------------------------------------------------------- ### [​](https://docs.arc.network/arc/tools/node-providers#alchemy) [Alchemy](https://www.alchemy.com/arc) Developer platform providing scalable access to EVM networks with enhanced APIs, monitoring, and debugging tools. ### [​](https://docs.arc.network/arc/tools/node-providers#blockdaemon) [Blockdaemon](https://www.blockdaemon.com/protocols/arc) Institutional-grade node provider offering secure and compliant infrastructure for Arc and other EVM chains. ### [​](https://docs.arc.network/arc/tools/node-providers#drpc) [dRPC](https://drpc.org/chainlist/arc-testnet-rpc) Decentralized RPC aggregator providing high-speed, load-balanced access to Arc nodes through a multi-provider architecture. ### [​](https://docs.arc.network/arc/tools/node-providers#quicknode) [QuickNode](https://www.quicknode.com/chains/arc) High-performance blockchain infrastructure offering global endpoints and APIs for developers. You can connect directly to Arc’s public RPC endpoint or through any of these infrastructure partners using your preferred SDK or web3 client. You can also [run your own node](https://docs.arc.network/arc/concepts/running-a-node) for independent verification and direct RPC access without third-party dependencies. Was this page helpful? YesNo [Data indexers](https://docs.arc.network/arc/tools/data-indexers) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Monitoring a node - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/monitor-a-node#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Run a Node Monitoring a node [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/arc/tutorials/monitor-a-node#prerequisites) * [Step 1. Check service status](https://docs.arc.network/arc/tutorials/monitor-a-node#step-1-check-service-status) * [Step 2. Check block height](https://docs.arc.network/arc/tutorials/monitor-a-node#step-2-check-block-height) * [Step 3. View the logs](https://docs.arc.network/arc/tutorials/monitor-a-node#step-3-view-the-logs) * [Step 4. Set up metrics scraping](https://docs.arc.network/arc/tutorials/monitor-a-node#step-4-set-up-metrics-scraping) Verify that your Arc node is syncing, diagnose issues from logs, and set up Prometheus metrics scraping. [​](https://docs.arc.network/arc/tutorials/monitor-a-node#prerequisites) Prerequisites ----------------------------------------------------------------------------------------- * You have a running Arc node that meets the [node requirements](https://docs.arc.network/arc/references/node-requirements) , set up either from the [Run an Arc Node](https://docs.arc.network/arc/tutorials/run-an-arc-node) tutorial or [deployed as a systemd service](https://docs.arc.network/arc/tutorials/deploy-node-as-service) * You have installed [Foundry](https://book.getfoundry.sh/getting-started/installation) , which provides the `cast` command * (Optional) You have installed [Prometheus](https://prometheus.io/) and [Grafana](https://grafana.com/) for metrics visualization [​](https://docs.arc.network/arc/tutorials/monitor-a-node#step-1-check-service-status) Step 1. Check service status ---------------------------------------------------------------------------------------------------------------------- If your node runs as systemd services, check the status of both processes: sudo systemctl status arc-execution sudo systemctl status arc-consensus Both services display `Active: active (running)` in their output. If either service has failed, review the logs in Step 3. [​](https://docs.arc.network/arc/tutorials/monitor-a-node#step-2-check-block-height) Step 2. Check block height ------------------------------------------------------------------------------------------------------------------ Query the local RPC endpoint to confirm the node is syncing: cast block-number --rpc-url http://localhost:8545 Run this command several times over a few seconds. The block number increases steadily, confirming the node is syncing: # First run: 1234567 # Second run (a few seconds later): 1234572 To view the latest block details: cast block --rpc-url http://localhost:8545 Example output: baseFeePerGas 7 difficulty 0 gasLimit 30000000 gasUsed 21000 hash 0xabc123... number 1234572 timestamp 1711234567 transactions: [0xdef456...] [​](https://docs.arc.network/arc/tutorials/monitor-a-node#step-3-view-the-logs) Step 3. View the logs -------------------------------------------------------------------------------------------------------- Stream real-time logs for each service: # Execution Layer logs sudo journalctl -u arc-execution -f # Consensus Layer logs sudo journalctl -u arc-consensus -f If your node is not running as a systemd service, check the terminal output where each process is running. **What to look for:** * **Healthy:** Log entries showing new blocks being imported, increasing block heights * **Unhealthy:** Repeated connection errors to relay endpoints, IPC socket failures, or no new blocks for an extended period [​](https://docs.arc.network/arc/tutorials/monitor-a-node#step-4-set-up-metrics-scraping) Step 4. Set up metrics scraping ---------------------------------------------------------------------------------------------------------------------------- Both the Execution Layer and Consensus Layer expose Prometheus-compatible metrics endpoints: | Endpoint | Description | | --- | --- | | `http://localhost:9001/metrics` | Execution Layer metrics | | `http://localhost:29000/metrics` | Consensus Layer metrics | The metrics endpoints are only available if the `--metrics` flag was passed when starting the node. The [Deploying a Node as a Service](https://docs.arc.network/arc/tutorials/deploy-node-as-service) guide includes this flag in the systemd service files.Verify the endpoints are accessible: curl -s http://localhost:9001/metrics | head -5 curl -s http://localhost:29000/metrics | head -5 Both commands return Prometheus-formatted text metrics. Example output: # HELP reth_sync_stage_checkpoint Stage checkpoint block number # TYPE reth_sync_stage_checkpoint gauge reth_sync_stage_checkpoint{stage="Headers"} 1234567 If either returns an empty response or connection error, confirm the `--metrics` flag is set in your startup command. Add the following scrape targets to your Prometheus configuration: scrape_configs: - job_name: "arc-execution" static_configs: - targets: ["localhost:9001"] - job_name: "arc-consensus" static_configs: - targets: ["localhost:29000"] After reloading Prometheus, verify that both targets appear as `UP` in the Prometheus targets page (`http://localhost:9090/targets`). Was this page helpful? YesNo [Deploying a node as a service](https://docs.arc.network/arc/tutorials/deploy-node-as-service) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Run an Arc node - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/run-an-arc-node#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Run a Node Run an Arc node [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Background](https://docs.arc.network/arc/tutorials/run-an-arc-node#background) * [Prerequisites](https://docs.arc.network/arc/tutorials/run-an-arc-node#prerequisites) * [Step 1: Install the node binaries](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-1-install-the-node-binaries) * [1.1. Install Rust](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-1-install-rust) * [1.2. Clone the repository](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-2-clone-the-repository) * [1.3. Build and install](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-3-build-and-install) * [1.4. Verify the installation](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-4-verify-the-installation) * [Step 2: Create data directories](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-2-create-data-directories) * [Step 3: Download blockchain snapshots](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-3-download-blockchain-snapshots) * [Step 4: Start the execution layer](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-4-start-the-execution-layer) * [Step 5: Initialize the consensus layer](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-5-initialize-the-consensus-layer) * [Step 6: Start the consensus layer](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-6-start-the-consensus-layer) * [Step 7: Verify the node is syncing](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-7-verify-the-node-is-syncing) * [Execution and consensus layer communication](https://docs.arc.network/arc/tutorials/run-an-arc-node#execution-and-consensus-layer-communication) * [Generate a JWT secret (one-time setup)](https://docs.arc.network/arc/tutorials/run-an-arc-node#generate-a-jwt-secret-one-time-setup) * [Execution layer flags for RPC mode](https://docs.arc.network/arc/tutorials/run-an-arc-node#execution-layer-flags-for-rpc-mode) * [Consensus layer flags for RPC mode](https://docs.arc.network/arc/tutorials/run-an-arc-node#consensus-layer-flags-for-rpc-mode) * [Enabling backpressure](https://docs.arc.network/arc/tutorials/run-an-arc-node#enabling-backpressure) Arc is currently in its testnet phase. During this period, the network may experience instability or unplanned downtime. Throughout this page, all references to Arc refer specifically to the Arc Testnet. An Arc node syncs blocks from the network and serves a local JSON-RPC endpoint, letting you independently verify every block and transaction. The node runs two processes: the Execution Layer (EL) and the Consensus Layer (CL). [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#background) Background ------------------------------------------------------------------------------------ An Arc node runs two processes that communicate through local IPC sockets. The Execution Layer executes transactions and maintains blockchain state. The Consensus Layer fetches blocks from relay endpoints, verifies their cryptographic signatures, and passes them to the Execution Layer for execution. For a deeper explanation of how these components work together, see [Running a Node](https://docs.arc.network/arc/concepts/running-a-node) . [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#prerequisites) Prerequisites ------------------------------------------------------------------------------------------ Before you begin, confirm that you have: * Reviewed the [Node Requirements](https://docs.arc.network/arc/references/node-requirements) for hardware specs, software, and network endpoints * Prepared a Linux machine that meets the minimum system requirements * Installed [Foundry](https://book.getfoundry.sh/getting-started/installation) (provides the `cast` command used to verify your node is syncing) [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-1-install-the-node-binaries) Step 1: Install the node binaries --------------------------------------------------------------------------------------------------------------------------------- Build `arc-node-execution`, `arc-node-consensus`, and `arc-snapshots` from source. ### [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-1-install-rust) 1.1. Install Rust Make sure you have [Rust](https://rust-lang.org/tools/install/) installed. If not, install it with the following commands: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.cargo/env ### [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-2-clone-the-repository) 1.2. Clone the repository Clone the [`arc-node`](https://github.com/circlefin/arc-node) repository and check out the version for your target network. See [Node Requirements](https://docs.arc.network/arc/references/node-requirements#versions) for the current version. git clone https://github.com/circlefin/arc-node.git cd arc-node git checkout v0.6.0 git submodule update --init --recursive ### [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-3-build-and-install) 1.3. Build and install The following commands build three Arc node binaries: `arc-node-execution`, `arc-node-consensus`, and `arc-snapshots`. cargo install --path crates/node cargo install --path crates/malachite-app cargo install --path crates/snapshots `cargo install` places compiled binaries into `~/.cargo/bin`, which is added to `PATH` by loading `~/.cargo/env`. Include the parameter `--root $BASE_DIR` to install the compiled binaries into `$BASE_DIR/bin` instead (for instance, `--root /usr/local`). ### [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#1-4-verify-the-installation) 1.4. Verify the installation arc-snapshots --version arc-node-execution --version arc-node-consensus --version Each command prints a version string. Example output: arc-snapshots 0.6.0 arc-node-execution 0.6.0 arc-node-consensus 0.6.0 [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-2-create-data-directories) Step 2: Create data directories ----------------------------------------------------------------------------------------------------------------------------- Create the directories where the EL and CL store their data, and set up the runtime directory for IPC sockets: mkdir -p ~/.arc/execution ~/.arc/consensus sudo install -d -o $USER /run/arc When running as a systemd service, the `RuntimeDirectory=arc` directive creates `/run/arc` automatically. You can skip the second command in that case. [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-3-download-blockchain-snapshots) Step 3: Download blockchain snapshots ----------------------------------------------------------------------------------------------------------------------------------------- Download snapshots to start syncing from a recent block height rather than from genesis. This significantly reduces initial sync time. arc-snapshots download --chain=arc-testnet This command fetches the latest snapshot URLs from `https://snapshots.arc.network`, downloads the snapshots, and extracts them into `~/.arc/execution` and `~/.arc/consensus` respectively. Snapshots are large files (approximately 60 GB download, 120+ GB extracted). This process is CPU and disk-intensive. Before downloading, ensure you have: * At least 150 GB of free disk space * A stable network connection * Available CPU resources (the process uses 40-70% CPU during extraction) The download and extraction can take 1-2 hours. The terminal stops producing output during extraction. This is expected behavior. [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-4-start-the-execution-layer) Step 4: Start the execution layer --------------------------------------------------------------------------------------------------------------------------------- Start the Execution Layer process. This creates the IPC sockets that the Consensus Layer connects to. arc-node-execution node \ --chain arc-testnet \ --datadir ~/.arc/execution \ --disable-discovery \ --ipcpath /run/arc/reth.ipc \ --auth-ipc \ --auth-ipc.path /run/arc/auth.ipc \ --http \ --http.addr 127.0.0.1 \ --http.port 8545 \ --http.api eth,net,web3,txpool,trace,debug \ --metrics 127.0.0.1:9001 \ --enable-arc-rpc \ --rpc.forwarder https://rpc.quicknode.testnet.arc.network/ The EL starts and begins waiting for blocks. Log output confirms the process is running and shows that the IPC sockets exist at `/run/arc/reth.ipc` and `/run/arc/auth.ipc`. | Flag | Required | Description | | --- | --- | --- | | `--chain arc-testnet` | Yes | Selects the Arc Testnet genesis configuration bundled in the binary | | `--datadir` | Yes | Path to the EL data directory | | `--disable-discovery` | Yes | Disables P2P peer discovery (Arc uses relay endpoints instead) | | `--ipcpath` / `--auth-ipc` | Yes (IPC mode) | Paths for the IPC sockets the CL connects to | | `--http` / `--http.addr` | Yes | Enables the JSON-RPC endpoint on the specified address and port | | `--http.api` | Recommended | RPC namespaces to expose | | `--metrics` | Recommended | Enables Prometheus metrics on the specified address and port | | `--enable-arc-rpc` | Yes | Enables Arc-specific RPC methods | | `--rpc.forwarder` | Recommended | Routes submitted transactions to an RPC node for broadcast | `--chain arc-testnet` uses the genesis configuration bundled in the binary. If you have a custom genesis file, replace with `--chain /path/to/genesis.json`.See [reth node](https://reth.rs/cli/reth/node/) for additional flags. [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-5-initialize-the-consensus-layer) Step 5: Initialize the consensus layer ------------------------------------------------------------------------------------------------------------------------------------------- Generate the private key file used for P2P network identity. This is a one-time setup step: arc-node-consensus init --home ~/.arc/consensus [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-6-start-the-consensus-layer) Step 6: Start the consensus layer --------------------------------------------------------------------------------------------------------------------------------- Open a separate terminal and start the Consensus Layer. The CL connects to the EL through the IPC sockets and begins fetching blocks from the network. arc-node-consensus start \ --home ~/.arc/consensus \ --eth-socket /run/arc/reth.ipc \ --execution-socket /run/arc/auth.ipc \ --rpc.addr 127.0.0.1:31000 \ --follow \ --follow.endpoint https://rpc.drpc.testnet.arc.network,wss=rpc.drpc.testnet.arc.network \ --follow.endpoint https://rpc.quicknode.testnet.arc.network,wss=rpc.quicknode.testnet.arc.network \ --follow.endpoint https://rpc.blockdaemon.testnet.arc.network,wss=rpc.blockdaemon.testnet.arc.network \ --metrics 127.0.0.1:29000 | Flag | Required | Description | | --- | --- | --- | | `--home` | Yes | Path to the CL data directory (contains keys and state) | | `--eth-socket` | Yes (IPC mode) | Path to the Execution Layer ETH RPC IPC socket | | `--execution-socket` | Yes (IPC mode) | Path to the Execution Layer Engine API IPC socket | | `--rpc.addr` | Recommended | CL RPC listen address and port | | `--follow` | Yes | Enables block-following mode through relay endpoints | | `--follow.endpoint` | Yes | Relay endpoint URLs. Specify multiple for redundancy. Format: `https://host,wss=host` | | `--metrics` | Recommended | Enables Prometheus metrics on the specified address and port | Start the Execution Layer first. The Consensus Layer connects to it on startup and fails if the EL is not running. [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#step-7-verify-the-node-is-syncing) Step 7: Verify the node is syncing ----------------------------------------------------------------------------------------------------------------------------------- Check that your node is syncing blocks by querying the local RPC endpoint: cast block-number --rpc-url http://localhost:8545 Run this command several times over a few seconds. The block number increases steadily, confirming your node is receiving and executing new blocks: # First run: 1234567 # Second run (a few seconds later): 1234572 To inspect the latest block: cast block --rpc-url http://localhost:8545 Example output: baseFeePerGas 7 difficulty 0 gasLimit 30000000 gasUsed 21000 hash 0xabc123... number 1234572 timestamp 1711234567 transactions: [0xdef456...] Once your node syncs steadily, you can [deploy it as a systemd service](https://docs.arc.network/arc/tutorials/deploy-node-as-service) for production use or [add monitoring](https://docs.arc.network/arc/tutorials/monitor-a-node) to observe sync status and metrics. For more on how the EL and CL interact, see [node architecture](https://docs.arc.network/arc/concepts/running-a-node#node-architecture) . [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#execution-and-consensus-layer-communication) Execution and consensus layer communication ------------------------------------------------------------------------------------------------------------------------------------------------------ The preceding steps use IPC sockets, which require the EL and CL to run on the same host. If they are on separate hosts, use RPC instead. ### [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#generate-a-jwt-secret-one-time-setup) Generate a JWT secret (one-time setup) The EL and CL use this secret to authenticate with each other: openssl rand -hex 32 | tr -d "\n" > ~/.arc/jwtsecret chmod 600 ~/.arc/jwtsecret ### [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#execution-layer-flags-for-rpc-mode) Execution layer flags for RPC mode Remove the IPC flags (`--ipcpath`, `--auth-ipc`, `--auth-ipc.path`) and add: --authrpc.addr 0.0.0.0 \ --authrpc.port 8551 \ --authrpc.jwtsecret ~/.arc/jwtsecret When using `--authrpc.addr 0.0.0.0`, restrict access to the Engine API port (8551) using firewall rules or a private network. The Engine API controls block production and must not be exposed to the public internet. ### [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#consensus-layer-flags-for-rpc-mode) Consensus layer flags for RPC mode Remove `--eth-socket` and `--execution-socket`, and add: --eth-rpc-endpoint http://:8545 \ --execution-endpoint http://:8551 \ --execution-jwt ~/.arc/jwtsecret IPC and RPC are mutually exclusive. Use one or the other, not both. [​](https://docs.arc.network/arc/tutorials/run-an-arc-node#enabling-backpressure) Enabling backpressure ---------------------------------------------------------------------------------------------------------- During startup or extended sync when the node is far behind, Execution Layer memory usage surges on some hardware. Backpressure, a mechanism that throttles execution to match the speed of disk writes, constrains this memory growth. To enable backpressure, add the `reth` namespace to the Execution Layer HTTP API flags: --http.api eth,net,web3,txpool,trace,debug,reth Then add the following flags to the Consensus Layer: --execution-persistence-backpressure \ --execution-persistence-backpressure-threshold=10 Arc node is alpha software. The team is actively working on this performance issue. Was this page helpful? YesNo [Node requirements](https://docs.arc.network/arc/references/node-requirements) [Deploying a node as a service](https://docs.arc.network/arc/tutorials/deploy-node-as-service) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Deploy on Arc - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/deploy-on-arc#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Deploy on Arc [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [What you’ll learn](https://docs.arc.network/arc/tutorials/deploy-on-arc#what-you%E2%80%99ll-learn) * [Set up your development environment](https://docs.arc.network/arc/tutorials/deploy-on-arc#set-up-your-development-environment) * [Configure Foundry to interact with Arc](https://docs.arc.network/arc/tutorials/deploy-on-arc#configure-foundry-to-interact-with-arc) * [Implement your smart contract](https://docs.arc.network/arc/tutorials/deploy-on-arc#implement-your-smart-contract) * [1\. Write the HelloArchitect contract](https://docs.arc.network/arc/tutorials/deploy-on-arc#1-write-the-helloarchitect-contract) * [2\. Update scripts and tests](https://docs.arc.network/arc/tutorials/deploy-on-arc#2-update-scripts-and-tests) * [3\. Test the contract](https://docs.arc.network/arc/tutorials/deploy-on-arc#3-test-the-contract) * [4\. Compile the contract](https://docs.arc.network/arc/tutorials/deploy-on-arc#4-compile-the-contract) * [Deploy your contract to Arc testnet](https://docs.arc.network/arc/tutorials/deploy-on-arc#deploy-your-contract-to-arc-testnet) * [1\. Generate a wallet](https://docs.arc.network/arc/tutorials/deploy-on-arc#1-generate-a-wallet) * [2\. Fund your wallet](https://docs.arc.network/arc/tutorials/deploy-on-arc#2-fund-your-wallet) * [3\. Deploy the contract](https://docs.arc.network/arc/tutorials/deploy-on-arc#3-deploy-the-contract) * [4\. Store the contract address](https://docs.arc.network/arc/tutorials/deploy-on-arc#4-store-the-contract-address) * [Interact with your deployed contract](https://docs.arc.network/arc/tutorials/deploy-on-arc#interact-with-your-deployed-contract) * [1\. Check transaction on the explorer](https://docs.arc.network/arc/tutorials/deploy-on-arc#1-check-transaction-on-the-explorer) * [2\. Use cast to call a contract function](https://docs.arc.network/arc/tutorials/deploy-on-arc#2-use-cast-to-call-a-contract-function) * [Next steps](https://docs.arc.network/arc/tutorials/deploy-on-arc#next-steps) Arc is currently in its testnet phase. During this period, the network may experience instability or unplanned downtime. **Note:** Throughout this page, all references to Arc refer specifically to the Arc Testnet. In this tutorial, you’ll use Solidity and Foundry to write, deploy, and interact with a simple smart contract on the Arc Testnet. [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#what-you%E2%80%99ll-learn) What you’ll learn -------------------------------------------------------------------------------------------------------- By the end of this tutorial, you’ll be able to: * Set up your development environment * Configure Foundry to connect with Arc * Implement your smart contract * Deploy your contract to Arc Testnet * Interact with your deployed contract [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#set-up-your-development-environment) Set up your development environment ------------------------------------------------------------------------------------------------------------------------------------ Before you deploy to Arc, you need a working development environment. In this step, you install [**Foundry**](https://getfoundry.sh/) , a portable Ethereum development toolkit, and initialize a new Solidity project. 1. Install Development Tools # Download foundry installer `foundryup` curl -L https://foundry.paradigm.xyz | bash 2. Install binaries # Install forge, cast, anvil, chisel foundryup 3. Initialize a new Solidity Project forge init hello-arc && cd hello-arc [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#configure-foundry-to-interact-with-arc) Configure Foundry to interact with Arc ------------------------------------------------------------------------------------------------------------------------------------------ In this step, you set up Foundry to connect to the Arc network by adding Arc’s RPC URLs to your project environment. 1. Create a `.env` file Open the `hello-arc` project in your preferred code editor (for example, **VS Code**). Then, create a new file named `.env` in the root of the project directory. 2. Add the Arc Testnet RPC URL Paste the following environment variable into the `.env` file: ARC_TESTNET_RPC_URL="https://rpc.testnet.arc.network" This URL allows Foundry to connect to the Arc Testnet. Never commit your `.env` file to version control. Store private keys and sensitive variables securely. [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#implement-your-smart-contract) Implement your smart contract ------------------------------------------------------------------------------------------------------------------------ In this step, you create the **HelloArchitect** contract, update the test and script files, and compile the project. **HelloArchitect** is a simple storage contract that manages a greeting message: it starts with a default greeting, lets you update it, and emits an event whenever the greeting changes. ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#1-write-the-helloarchitect-contract) 1\. Write the HelloArchitect contract First, delete the default `Counter.sol` template file from the `/src` directory: rm src/Counter.sol Next, create a new file named `HelloArchitect.sol` inside the `/src` directory, and add the following code: // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; contract HelloArchitect { string private greeting; // Event emitted when the greeting is changed event GreetingChanged(string newGreeting); // Constructor that sets the initial greeting to "Hello Architect!" constructor() { greeting = "Hello Architect!"; } // Setter function to update the greeting function setGreeting(string memory newGreeting) public { greeting = newGreeting; emit GreetingChanged(newGreeting); } // Getter function to return the current greeting function getGreeting() public view returns (string memory) { return greeting; } } This contract includes a private `greeting` variable that stores the greeting string, along with two public functions: * `setGreeting` updates the `greeting` value and emits the `GreetingChanged` event * `getGreeting` returns the current value of `greeting` ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#2-update-scripts-and-tests) 2\. Update scripts and tests Since you deleted `Counter.sol`, you need to remove or replace any scripts and tests that reference it to avoid compilation errors. **Delete the `script` directory** The `script` directory includes files that reference `Counter.sol`. Since you’ve removed `Counter.sol`, delete the entire `script` directory to avoid compilation errors: rm -rf script You can recreate this directory later with updated deployment scripts for your own contracts. **Replace `Counter.t.sol` with `HelloArchitect.t.sol`** Navigate to the `/test` directory, delete the existing `Counter.t.sol` file, and create a new test file named `HelloArchitect.t.sol`. Then, add the following test cases to validate your contract: // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import "forge-std/Test.sol"; import "../src/HelloArchitect.sol"; contract HelloArchitectTest is Test { HelloArchitect helloArchitect; function setUp() public { helloArchitect = new HelloArchitect(); } function testInitialGreeting() public view { string memory expected = "Hello Architect!"; string memory actual = helloArchitect.getGreeting(); assertEq(actual, expected); } function testSetGreeting() public { string memory newGreeting = "Welcome to Arc Chain!"; helloArchitect.setGreeting(newGreeting); string memory actual = helloArchitect.getGreeting(); assertEq(actual, newGreeting); } function testGreetingChangedEvent() public { string memory newGreeting = "Building on Arc!"; // Expect the GreetingChanged event to be emitted vm.expectEmit(true, true, true, true); emit HelloArchitect.GreetingChanged(newGreeting); helloArchitect.setGreeting(newGreeting); } } ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#3-test-the-contract) 3\. Test the contract Run the following command to execute the contract’s unit tests locally: forge test This will compile the project, run the tests defined in `HelloArchitect.t.sol`, and display the results in your terminal. ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#4-compile-the-contract) 4\. Compile the contract To compile the **HelloArchitect** contract and generate build artifacts, run: forge build This creates the `/out` directory containing the compiled bytecode and ABI, which you’ll use when deploying the contract. [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#deploy-your-contract-to-arc-testnet) Deploy your contract to Arc testnet ------------------------------------------------------------------------------------------------------------------------------------ In this step, you generate a wallet, fund it with testnet USDC (Arc’s native gas token), and deploy your smart contract to the Arc Testnet using Foundry. ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#1-generate-a-wallet) 1\. Generate a wallet To deploy the **HelloArchitect** contract, you need a funded wallet. Use the Foundry command-line tool to generate a new wallet: cast wallet new The command generates a new keypair and returns output similar to the following: Successfully created new keypair. Address: 0xB815A0c4bC23930119324d4359dB65e27A846A2d Private key: 0xcc1b30a6af68ea9a9917f1dd••••••••••••••••••••••••••••••••••••••97c5 **Important:** Keep your private key secure. Never share it or commit it to source control. Add your private key to your `.env` file: PRIVATE_KEY="0x..." Reload your environment variables: source .env ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#2-fund-your-wallet) 2\. Fund your wallet Visit the [Circle Faucet](https://faucet.circle.com/) , select **Arc Testnet**, paste your wallet address, and request testnet USDC. Since USDC is Arc’s native gas token, this will provide the funds needed to cover gas fees when deploying your contract. Testnet USDC is for testing purposes only. It has no real-world value and must not be used in production. ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#3-deploy-the-contract) 3\. Deploy the contract With your wallet funded with testnet USDC, deploy the **HelloArchitect** contract to the Arc Testnet using the Foundry command-line tool: forge create src/HelloArchitect.sol:HelloArchitect \ --rpc-url $ARC_TESTNET_RPC_URL \ --private-key $PRIVATE_KEY \ --broadcast **Important:** Never expose your real private key in production. Use environment variables or secrets management in real deployments. After the contract is deployed successfully, you should see output similar to this: Compiler run successful! Deployer: 0xB815A0c4bC23930119324d4359dB65e27A846A2d Deployed to: 0x32368037b14819C9e5Dbe96b3d67C59b8c65c4BF Transaction hash: 0xeba0fcb5e528d586db0aeb2465a8fad0299330a9773ca62818a1827560a67346 ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#4-store-the-contract-address) 4\. Store the contract address Copy the deployed contract address from the `Deployed to:` line and save it to your `.env` file: HELLOARCHITECT_ADDRESS="0x..." Reload your environment variables again: source .env [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#interact-with-your-deployed-contract) Interact with your deployed contract -------------------------------------------------------------------------------------------------------------------------------------- In this step, you verify that the deployment succeeded by checking the transaction in the Arc Testnet Explorer, then use `cast` to call a function from your contract. ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#1-check-transaction-on-the-explorer) 1\. Check transaction on the explorer Open the [Arc Testnet Explorer](https://testnet.arcscan.app/) , and paste the **transaction hash** from the deployment output. This lets you view the transaction details and confirm that the contract was deployed successfully. ### [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#2-use-cast-to-call-a-contract-function) 2\. Use `cast` to call a contract function Use the `cast call` command to interact with your deployed contract from the command line. Run the following: cast call $HELLOARCHITECT_ADDRESS "getGreeting()(string)" \ --rpc-url $ARC_TESTNET_RPC_URL The command calls the `getGreeting` function on the **HelloArchitect** contract and returns the current value of the `greeting` variable. [​](https://docs.arc.network/arc/tutorials/deploy-on-arc#next-steps) Next steps ---------------------------------------------------------------------------------- Congratulations, you’ve deployed and interacted with your first contract on Arc Testnet. From here, you can: * Extend the **HelloArchitect** contract with more logic for additional features. * Explore Arc’s stablecoin-native features like USDC as gas and deterministic finality * Build more advanced applications for payments, FX, or tokenized assets Was this page helpful? YesNo [Connect to Arc](https://docs.arc.network/arc/references/connect-to-arc) [MCP server](https://docs.arc.network/ai/mcp) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Connect to Arc - Arc Docs [Skip to main content](https://docs.arc.network/integrate/connect-to-arc#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Connect to Arc [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Network details](https://docs.arc.network/integrate/connect-to-arc#network-details) * [Arc testnet](https://docs.arc.network/integrate/connect-to-arc#arc-testnet) * [Wallet setup](https://docs.arc.network/integrate/connect-to-arc#wallet-setup) * [Add Arc testnet](https://docs.arc.network/integrate/connect-to-arc#add-arc-testnet) * [Gas and fees](https://docs.arc.network/integrate/connect-to-arc#gas-and-fees) [​](https://docs.arc.network/integrate/connect-to-arc#network-details) Network details ----------------------------------------------------------------------------------------- ### [​](https://docs.arc.network/integrate/connect-to-arc#arc-testnet) Arc testnet | Name | Value | | --- | --- | | **Network** | Arc Testnet | | **RPC endpoint** | `https://rpc.testnet.arc.network`
Alternatives:
  • `https://rpc.blockdaemon.testnet.arc.network`
  • `https://rpc.drpc.testnet.arc.network`
  • `https://rpc.quicknode.testnet.arc.network` | | **WebSocket** | `wss://rpc.testnet.arc.network`
Alternatives:
  • `wss://rpc.drpc.testnet.arc.network`
  • `wss://rpc.quicknode.testnet.arc.network` | | **Chain ID** | 5042002 | | **Currency** | USDC | | **Explorer** | `https://testnet.arcscan.app` | | **Faucet** | `https://faucet.circle.com` | [​](https://docs.arc.network/integrate/connect-to-arc#wallet-setup) Wallet setup ----------------------------------------------------------------------------------- ### [​](https://docs.arc.network/integrate/connect-to-arc#add-arc-testnet) Add Arc testnet 1. Open MetaMask → **Add network** → **Add a network manually**. 2. Fill in: | Field | Value | | --- | --- | | **Network name** | Arc Testnet | | **New RPC URL** | `https://rpc.testnet.arc.network` | | **Chain ID** | 5042002 | | **Currency symbol** | USDC | | **Explorer URL** | `https://testnet.arcscan.app` | 3. Save, then switch to Arc. If your wallet supports **custom gas tokens**, ensure display/decimals for USDC (18 decimals) and clearly label fees as USDC. [​](https://docs.arc.network/integrate/connect-to-arc#gas-and-fees) Gas and fees ----------------------------------------------------------------------------------- Arc uses USDC as the native gas token. For details on gas configuration and the current base fee policy, see the [Gas and Fees](https://docs.arc.network/arc/references/gas-and-fees) page. Was this page helpful? YesNo [Overview](https://docs.arc.network/integrate) [Deploy on Arc](https://docs.arc.network/integrate/deploy-on-arc) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Build on Arc - Arc Docs [Skip to main content](https://docs.arc.network/build#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Build on Arc [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Get started](https://docs.arc.network/build#get-started) * [Quickstarts](https://docs.arc.network/build#quickstarts) * [App Kit](https://docs.arc.network/build#app-kit) * [Developer tools](https://docs.arc.network/build#developer-tools) * [Sample applications](https://docs.arc.network/build#sample-applications) Arc gives you a complete developer platform for building financial applications with stablecoins. Whether you’re deploying smart contracts, moving USDC across chains, or building payment workflows with App Kit, everything starts here. [​](https://docs.arc.network/build#get-started) Get started -------------------------------------------------------------- Connect to Arc -------------- RPC endpoints, chain ID, and network configuration for Arc testnet. Deploy on Arc ------------- Deploy, test, and interact with a Solidity smart contract on Arc. [​](https://docs.arc.network/build#quickstarts) Quickstarts -------------------------------------------------------------- Step-by-step guides to get a working integration running in minutes. | Quickstart | What you’ll build | | --- | --- | | [Deploy contracts](https://docs.arc.network/arc/tutorials/deploy-contracts) | Deploy ERC-20, ERC-721, and ERC-1155 contracts on Arc testnet. | | [Transfer stablecoins](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc) | Send USDC or EURC between wallets on Arc. | | [Bridge USDC to Arc](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc) | Move USDC from another blockchain to Arc using CCTP. | | [Access USDC crosschain](https://docs.arc.network/arc/tutorials/access-usdc-crosschain) | Deposit and withdraw USDC through Circle Gateway. | | [Interact with contracts](https://docs.arc.network/arc/tutorials/interact-with-contracts) | Mint, transfer, and airdrop tokens using deployed contracts. | | [Monitor contract events](https://docs.arc.network/arc/tutorials/monitor-contract-events) | Set up webhooks and event monitors for onchain activity. | [​](https://docs.arc.network/build#app-kit) App Kit ------------------------------------------------------ [App Kit](https://docs.arc.network/app-kit) is an SDK for building payment and liquidity workflows across blockchains. Add bridging, swapping, and token transfers to your app in a few lines of code. Bridge ------ Transfer USDC across blockchains using CCTP. Swap ---- Exchange one token for another on the same blockchain. Send ---- Transfer tokens between wallets on the same blockchain. See the full [installation guide](https://docs.arc.network/app-kit/tutorials/installation) to get started, or browse [supported blockchains](https://docs.arc.network/app-kit/references/supported-blockchains) and the [SDK reference](https://docs.arc.network/app-kit/references/sdk-reference) . [​](https://docs.arc.network/build#developer-tools) Developer tools ---------------------------------------------------------------------- Account abstraction ------------------- Smart wallets, paymasters, and session keys from ecosystem providers. Node providers -------------- Managed RPC access from Alchemy, QuickNode, Blockdaemon, and dRPC. Data indexers ------------- Query onchain data with Envio, Goldsky, The Graph, and Thirdweb. Compliance ---------- Transaction monitoring and wallet screening from Elliptic and TRM Labs. [​](https://docs.arc.network/build#sample-applications) Sample applications ------------------------------------------------------------------------------ Browse working examples and reference implementations in the [sample apps](https://docs.arc.network/arc/references/sample-applications) gallery. Was this page helpful? YesNo [Sample apps](https://docs.arc.network/arc/references/sample-applications) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Deploy on Arc - Arc Docs [Skip to main content](https://docs.arc.network/integrate/deploy-on-arc#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Deploy on Arc [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [What you’ll learn](https://docs.arc.network/integrate/deploy-on-arc#what-you%E2%80%99ll-learn) * [Set up your development environment](https://docs.arc.network/integrate/deploy-on-arc#set-up-your-development-environment) * [Configure Foundry to interact with Arc](https://docs.arc.network/integrate/deploy-on-arc#configure-foundry-to-interact-with-arc) * [Implement your smart contract](https://docs.arc.network/integrate/deploy-on-arc#implement-your-smart-contract) * [1\. Write the HelloArchitect contract](https://docs.arc.network/integrate/deploy-on-arc#1-write-the-helloarchitect-contract) * [2\. Update scripts and tests](https://docs.arc.network/integrate/deploy-on-arc#2-update-scripts-and-tests) * [3\. Test the contract](https://docs.arc.network/integrate/deploy-on-arc#3-test-the-contract) * [4\. Compile the contract](https://docs.arc.network/integrate/deploy-on-arc#4-compile-the-contract) * [Deploy your contract to Arc testnet](https://docs.arc.network/integrate/deploy-on-arc#deploy-your-contract-to-arc-testnet) * [1\. Generate a wallet](https://docs.arc.network/integrate/deploy-on-arc#1-generate-a-wallet) * [2\. Fund your wallet](https://docs.arc.network/integrate/deploy-on-arc#2-fund-your-wallet) * [3\. Deploy the contract](https://docs.arc.network/integrate/deploy-on-arc#3-deploy-the-contract) * [4\. Store the contract address](https://docs.arc.network/integrate/deploy-on-arc#4-store-the-contract-address) * [Interact with your deployed contract](https://docs.arc.network/integrate/deploy-on-arc#interact-with-your-deployed-contract) * [1\. Check transaction on the explorer](https://docs.arc.network/integrate/deploy-on-arc#1-check-transaction-on-the-explorer) * [2\. Use cast to call a contract function](https://docs.arc.network/integrate/deploy-on-arc#2-use-cast-to-call-a-contract-function) * [Next steps](https://docs.arc.network/integrate/deploy-on-arc#next-steps) Arc is currently in its testnet phase. During this period, the network may experience instability or unplanned downtime. **Note:** Throughout this page, all references to Arc refer specifically to the Arc Testnet. In this tutorial, you’ll use Solidity and Foundry to write, deploy, and interact with a simple smart contract on the Arc Testnet. [​](https://docs.arc.network/integrate/deploy-on-arc#what-you%E2%80%99ll-learn) What you’ll learn ---------------------------------------------------------------------------------------------------- By the end of this tutorial, you’ll be able to: * Set up your development environment * Configure Foundry to connect with Arc * Implement your smart contract * Deploy your contract to Arc Testnet * Interact with your deployed contract [​](https://docs.arc.network/integrate/deploy-on-arc#set-up-your-development-environment) Set up your development environment -------------------------------------------------------------------------------------------------------------------------------- Before you deploy to Arc, you need a working development environment. In this step, you install [**Foundry**](https://getfoundry.sh/) , a portable Ethereum development toolkit, and initialize a new Solidity project. 1. Install Development Tools # Download foundry installer `foundryup` curl -L https://foundry.paradigm.xyz | bash 2. Install binaries # Install forge, cast, anvil, chisel foundryup 3. Initialize a new Solidity Project forge init hello-arc && cd hello-arc [​](https://docs.arc.network/integrate/deploy-on-arc#configure-foundry-to-interact-with-arc) Configure Foundry to interact with Arc -------------------------------------------------------------------------------------------------------------------------------------- In this step, you set up Foundry to connect to the Arc network by adding Arc’s RPC URLs to your project environment. 1. Create a `.env` file Open the `hello-arc` project in your preferred code editor (for example, **VS Code**). Then, create a new file named `.env` in the root of the project directory. 2. Add the Arc Testnet RPC URL Paste the following environment variable into the `.env` file: ARC_TESTNET_RPC_URL="https://rpc.testnet.arc.network" This URL allows Foundry to connect to the Arc Testnet. Never commit your `.env` file to version control. Store private keys and sensitive variables securely. [​](https://docs.arc.network/integrate/deploy-on-arc#implement-your-smart-contract) Implement your smart contract -------------------------------------------------------------------------------------------------------------------- In this step, you create the **HelloArchitect** contract, update the test and script files, and compile the project. **HelloArchitect** is a simple storage contract that manages a greeting message: it starts with a default greeting, lets you update it, and emits an event whenever the greeting changes. ### [​](https://docs.arc.network/integrate/deploy-on-arc#1-write-the-helloarchitect-contract) 1\. Write the HelloArchitect contract First, delete the default `Counter.sol` template file from the `/src` directory: rm src/Counter.sol Next, create a new file named `HelloArchitect.sol` inside the `/src` directory, and add the following code: // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; contract HelloArchitect { string private greeting; // Event emitted when the greeting is changed event GreetingChanged(string newGreeting); // Constructor that sets the initial greeting to "Hello Architect!" constructor() { greeting = "Hello Architect!"; } // Setter function to update the greeting function setGreeting(string memory newGreeting) public { greeting = newGreeting; emit GreetingChanged(newGreeting); } // Getter function to return the current greeting function getGreeting() public view returns (string memory) { return greeting; } } This contract includes a private `greeting` variable that stores the greeting string, along with two public functions: * `setGreeting` updates the `greeting` value and emits the `GreetingChanged` event * `getGreeting` returns the current value of `greeting` ### [​](https://docs.arc.network/integrate/deploy-on-arc#2-update-scripts-and-tests) 2\. Update scripts and tests Since you deleted `Counter.sol`, you need to remove or replace any scripts and tests that reference it to avoid compilation errors. **Delete the `script` directory** The `script` directory includes files that reference `Counter.sol`. Since you’ve removed `Counter.sol`, delete the entire `script` directory to avoid compilation errors: rm -rf script You can recreate this directory later with updated deployment scripts for your own contracts. **Replace `Counter.t.sol` with `HelloArchitect.t.sol`** Navigate to the `/test` directory, delete the existing `Counter.t.sol` file, and create a new test file named `HelloArchitect.t.sol`. Then, add the following test cases to validate your contract: // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import "forge-std/Test.sol"; import "../src/HelloArchitect.sol"; contract HelloArchitectTest is Test { HelloArchitect helloArchitect; function setUp() public { helloArchitect = new HelloArchitect(); } function testInitialGreeting() public view { string memory expected = "Hello Architect!"; string memory actual = helloArchitect.getGreeting(); assertEq(actual, expected); } function testSetGreeting() public { string memory newGreeting = "Welcome to Arc Chain!"; helloArchitect.setGreeting(newGreeting); string memory actual = helloArchitect.getGreeting(); assertEq(actual, newGreeting); } function testGreetingChangedEvent() public { string memory newGreeting = "Building on Arc!"; // Expect the GreetingChanged event to be emitted vm.expectEmit(true, true, true, true); emit HelloArchitect.GreetingChanged(newGreeting); helloArchitect.setGreeting(newGreeting); } } ### [​](https://docs.arc.network/integrate/deploy-on-arc#3-test-the-contract) 3\. Test the contract Run the following command to execute the contract’s unit tests locally: forge test This will compile the project, run the tests defined in `HelloArchitect.t.sol`, and display the results in your terminal. ### [​](https://docs.arc.network/integrate/deploy-on-arc#4-compile-the-contract) 4\. Compile the contract To compile the **HelloArchitect** contract and generate build artifacts, run: forge build This creates the `/out` directory containing the compiled bytecode and ABI, which you’ll use when deploying the contract. [​](https://docs.arc.network/integrate/deploy-on-arc#deploy-your-contract-to-arc-testnet) Deploy your contract to Arc testnet -------------------------------------------------------------------------------------------------------------------------------- In this step, you generate a wallet, fund it with testnet USDC (Arc’s native gas token), and deploy your smart contract to the Arc Testnet using Foundry. ### [​](https://docs.arc.network/integrate/deploy-on-arc#1-generate-a-wallet) 1\. Generate a wallet To deploy the **HelloArchitect** contract, you need a funded wallet. Use the Foundry command-line tool to generate a new wallet: cast wallet new The command generates a new keypair and returns output similar to the following: Successfully created new keypair. Address: 0xB815A0c4bC23930119324d4359dB65e27A846A2d Private key: 0xcc1b30a6af68ea9a9917f1dd••••••••••••••••••••••••••••••••••••••97c5 **Important:** Keep your private key secure. Never share it or commit it to source control. Add your private key to your `.env` file: PRIVATE_KEY="0x..." Reload your environment variables: source .env ### [​](https://docs.arc.network/integrate/deploy-on-arc#2-fund-your-wallet) 2\. Fund your wallet Visit the [Circle Faucet](https://faucet.circle.com/) , select **Arc Testnet**, paste your wallet address, and request testnet USDC. Since USDC is Arc’s native gas token, this will provide the funds needed to cover gas fees when deploying your contract. Testnet USDC is for testing purposes only. It has no real-world value and must not be used in production. ### [​](https://docs.arc.network/integrate/deploy-on-arc#3-deploy-the-contract) 3\. Deploy the contract With your wallet funded with testnet USDC, deploy the **HelloArchitect** contract to the Arc Testnet using the Foundry command-line tool: forge create src/HelloArchitect.sol:HelloArchitect \ --rpc-url $ARC_TESTNET_RPC_URL \ --private-key $PRIVATE_KEY \ --broadcast **Important:** Never expose your real private key in production. Use environment variables or secrets management in real deployments. After the contract is deployed successfully, you should see output similar to this: Compiler run successful! Deployer: 0xB815A0c4bC23930119324d4359dB65e27A846A2d Deployed to: 0x32368037b14819C9e5Dbe96b3d67C59b8c65c4BF Transaction hash: 0xeba0fcb5e528d586db0aeb2465a8fad0299330a9773ca62818a1827560a67346 ### [​](https://docs.arc.network/integrate/deploy-on-arc#4-store-the-contract-address) 4\. Store the contract address Copy the deployed contract address from the `Deployed to:` line and save it to your `.env` file: HELLOARCHITECT_ADDRESS="0x..." Reload your environment variables again: source .env [​](https://docs.arc.network/integrate/deploy-on-arc#interact-with-your-deployed-contract) Interact with your deployed contract ---------------------------------------------------------------------------------------------------------------------------------- In this step, you verify that the deployment succeeded by checking the transaction in the Arc Testnet Explorer, then use `cast` to call a function from your contract. ### [​](https://docs.arc.network/integrate/deploy-on-arc#1-check-transaction-on-the-explorer) 1\. Check transaction on the explorer Open the [Arc Testnet Explorer](https://testnet.arcscan.app/) , and paste the **transaction hash** from the deployment output. This lets you view the transaction details and confirm that the contract was deployed successfully. ### [​](https://docs.arc.network/integrate/deploy-on-arc#2-use-cast-to-call-a-contract-function) 2\. Use `cast` to call a contract function Use the `cast call` command to interact with your deployed contract from the command line. Run the following: cast call $HELLOARCHITECT_ADDRESS "getGreeting()(string)" \ --rpc-url $ARC_TESTNET_RPC_URL The command calls the `getGreeting` function on the **HelloArchitect** contract and returns the current value of the `greeting` variable. [​](https://docs.arc.network/integrate/deploy-on-arc#next-steps) Next steps ------------------------------------------------------------------------------ Congratulations, you’ve deployed and interacted with your first contract on Arc Testnet. From here, you can: * Extend the **HelloArchitect** contract with more logic for additional features. * Explore Arc’s stablecoin-native features like USDC as gas and deterministic finality * Build more advanced applications for payments, FX, or tokenized assets Was this page helpful? YesNo [Connect to Arc](https://docs.arc.network/integrate/connect-to-arc) [EVM compatibility](https://docs.arc.network/arc/references/evm-compatibility) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Terms of Service - Arc Docs [Skip to main content](https://docs.arc.network/terms#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Terms of Service [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Your Access to and Use of the Testnet](https://docs.arc.network/terms#your-access-to-and-use-of-the-testnet) * [Testnet Access Prohibitions](https://docs.arc.network/terms#testnet-access-prohibitions) * [Connecting Digital Wallet](https://docs.arc.network/terms#connecting-digital-wallet) * [Testnet Tokens](https://docs.arc.network/terms#testnet-tokens) * [No Agency](https://docs.arc.network/terms#no-agency) * [No Financial Services](https://docs.arc.network/terms#no-financial-services) * [Submission of User Content](https://docs.arc.network/terms#submission-of-user-content) * [Digital Millennium Copyright Act](https://docs.arc.network/terms#digital-millennium-copyright-act) * [Use of the Company Marks](https://docs.arc.network/terms#use-of-the-company-marks) * [Ownership; Feedback](https://docs.arc.network/terms#ownership-feedback) * [Termination](https://docs.arc.network/terms#termination) * [No Warranties](https://docs.arc.network/terms#no-warranties) * [Limitation of Liability](https://docs.arc.network/terms#limitation-of-liability) * [Indemnity](https://docs.arc.network/terms#indemnity) * [Modification of Terms](https://docs.arc.network/terms#modification-of-terms) * [Dispute Resolution; Binding Individual Arbitration; Class Action Waiver](https://docs.arc.network/terms#dispute-resolution-binding-individual-arbitration-class-action-waiver) * [Governing Law](https://docs.arc.network/terms#governing-law) * [Limitation on Time to Initiate a Dispute](https://docs.arc.network/terms#limitation-on-time-to-initiate-a-dispute) * [Assignment; Change of Control](https://docs.arc.network/terms#assignment-change-of-control) * [Other Provisions](https://docs.arc.network/terms#other-provisions) * [Survival](https://docs.arc.network/terms#survival) _**Last Updated: October 2, 2025**_ These Arc Network Terms of Service (these “Terms” or this “Agreement”) constitute a binding legal agreement between you (“you,” “your”) and Circle Technology Services, LLC (on behalf of itself and any other affiliates to the extent relevant) (“Company” “we,” “our” or “us”) governing your use of the Arc Network Testnet (the “Testnet”). The Testnet is a temporary, pre-production environment operated by the Company and is intended solely for testing, experimentation, and research purposes. The Testnet is not a production network, and does not process, transfer, or store real money or digital assets of value. If you are an individual accessing or using the Testnet on behalf of, or for the benefit of, any corporation, partnership or other entity with which you are associated (an “Organization”), then you are agreeing to this Agreement on behalf of yourself and such Organization, and you represent and warrant that you have the legal authority to bind such Organization to this Agreement. By using or accessing the Testnet, you agree to be bound by these Terms and any documentation and guidelines accompanying the Testnet, and all other terms, policies, and guidelines applicable to your use. You acknowledge and agree that your use of the Testnet is at your own risk and the Company is not responsible for any losses that occur as a result of your use of the Testnet. **THESE TERMS CONTAIN A MANDATORY [ARBITRATION PROVISION AND CLASS ACTION WAIVER THAT](https://docs.arc.network/terms#dispute-resolution%3B-binding-individual-arbitration%3B-class-action-waiver) , AS FURTHER SET FORTH BELOW, REQUIRES THE USE OF ARBITRATION ON AN INDIVIDUAL BASIS TO RESOLVE DISPUTES, RATHER THAN JURY TRIALS OR ANY OTHER COURT PROCEEDINGS, OR CLASS ACTIONS OF ANY KIND.** 1. [​](https://docs.arc.network/terms#your-access-to-and-use-of-the-testnet) Your Access to and Use of the Testnet ------------------------------------------------------------------------------------------------------------------ 1. You must be at least 18 years and be legally capable of forming a binding contract in your country of residence to use the Testnet. 2. You are not a person barred from using the Testnet under the laws of the United States, your place of residence, or any other applicable jurisdiction. 3. By accessing and using the Testnet, you agree that you have read, understand and accept (i) all of the terms and conditions contained in these Terms and (ii) the Company’s [Privacy Policy](https://www.circle.com/legal/privacy-policy) , [Cookie Policy](https://www.circle.com/legal/cookie-policy) , and [E-Sign Consent Policy](https://www.circle.com/legal/esign-consent) . You acknowledge and agree that you will be bound by these Terms and any other applicable agreements and policies upon access and use of the Testnet. 4. You are knowledgeable, experienced, and sophisticated in using and evaluating blockchain and related technologies and assets, including the Testnet. 5. You may only use the Testnet for lawful testing, experimentation, and evaluation. 6. The Company may reset, restart, modify, update, or shut down the Testnet at any time and may discontinue support for the Testnet at the Company’s sole discretion. For the avoidance of doubt, we may, at our sole option and election, terminate access to the Testnet at any time. We also reserve the right, in our sole discretion, to prohibit certain wallet addresses from being able to use or engage with the Testnet at any time. We will not be liable for any losses suffered by you resulting from any modification to the Testnet or from any suspension or termination, for any reason, of your access to all or any portion of the Testnet. 7. Your use of the Testnet is subject to certain limitations on access and use as set forth in these Terms, any documentation accompanying the Testnet or as otherwise provided to you by the Company. You agree that: (i) you will not misrepresent or mask your identity when using the Testnet; (ii) you will avoid any conflict of interest or engage in any intentional unethical conduct; and (iii) you will not intentionally or negligently cause any reputational harm to the Company. If the Company believes that you have attempted to exceed or circumvent these limitations, your ability to use the Testnet may be temporarily or permanently blocked without prior notice. 8. You may receive updates and information from the Company that constitute Confidential Information. “Confidential Information” means any information or data, regardless of whether it is in tangible form, that is disclosed or otherwise made available by the Company to you and that is (i) in tangible form and labeled or marked confidential or proprietary, (ii) if disclosed orally is designated as confidential or proprietary at time of disclosure, or (iii) information that a reasonable person knows or should have known to be confidential or proprietary given the nature of the information and the circumstances surrounding disclosure. Any information disclosed by an affiliate of the Company shall be treated as if disclosed by the Company. All Confidential Information is the sole and exclusive property of the Company and may be used by you only for assisting us in resolving any security issue you have reported to us. You agree not to disclose such Confidential Information or any announcement that the Company notes as embargoed without the Company’s prior written consent. You may disclose Confidential Information when compelled to do so by Legal Requirements if you provide us with reasonable prior notice unless a court orders that we not receive notice. 9. You acknowledge and understand that: (i) activity on the Testnet is public and may be viewed or recorded by anyone; (ii) you should not input personal, confidential, or proprietary information into the Testnet; and (iii) the Company may collect limited telemetry or usage data to improve and evaluate the Testnet. 10. If applicable, the Company may use your data and information you may provide solely to the extent necessary to fulfill its obligations under these Terms and to comply with applicable Legal Requirements. 11. You agree to comply with any and all applicable “Data Protection Law(s)” (which means, collectively, all Legal Requirements that apply to processing of personal data under or in connection with these Terms, including applicable international, national, federal, state, provincial, and local laws, rules, regulations, directives and governmental requirements relating to privacy, data protection, or security) that may apply to performing your obligations under these Terms. The obligations include, without limitation: 1. providing notices of data breach as required by applicable Data Protection Laws; and 2. processing data only in accordance with the Company’s privacy policy, as well as your own privacy policies. 12. You and the Company agree that neither is the data processor of the other party under any applicable Data Protection Law, nor are you and us acting together as joint data controllers. To the extent any personal data is processed in connection with the Testnet, each party acts as an independent controller with respect to its own processing of such personal data. You and the Company further agree that no monetary or other valuable consideration is provided to either party in exchange for any personal data associated with the Testnet and that data sharing conducted pursuant to these Terms does not constitute a sale of personal data under any applicable Data Protection Law. 13. You agree to be solely responsible for the accuracy, quality, integrity and legality of all information you share with the Company or its affiliates. 14. You acknowledge and agree that, in providing the Testnet, the Company is not acting in any capacity as a money transmitter or money services business (or equivalent regulated entity under applicable Legal Requirements), and the Company does not provide any regulated financial services in connection with the Testnet. 15. You are responsible for obtaining the data network access necessary to use the Testnet. Mobile network data and messaging rates and fees may apply if you access or use the Testnet from a mobile device. You are responsible for acquiring and updating compatible hardware or devices necessary to access and use the Testnet and any updates thereto. The Company does not guarantee that the Testnet, or any portion thereof, will function on any particular hardware or devices. In addition, the Testnet may be subject to malfunctions and delays inherent in the use of the Internet and electronic communications. We are not responsible for any delays, delivery failures, or damage, loss or injury resulting from any such issues. 16. Third parties may elect to support or utilize the Testnet on their platforms without any authorization or approval by the Company or anyone else. For example, as a result of the decentralized and open source nature of the Testnet, it is possible that a party unaffiliated with the Company could create an alternative version of the blockchain (a “fork”). Testnet access or support on any third-party platform does not imply any endorsement by the Company that such third-party services are valid, legal, stable or otherwise appropriate. The Company is not responsible for any losses or other issues you might encounter using the Testnet in connection with any third-party forks, platforms, blockchains, protocols, technologies, products or services. The Company does not have any ability or obligation to prevent or mitigate attacks or resolve any other issues that might arise with any third-party forks, platforms, blockchains, protocols, technologies, products or services. Any such attacks or issues related to any third party might materially impact you, and the Company shall bear no responsibility for any losses that result from such attacks or issues. It is your responsibility to ensure that you are accessing the Testnet through your intended user interface. 17. You are aware of and accept the risk of operational challenges with the Testnet. The Company may experience sophisticated cyber-attacks, unexpected surges in activity or other operational or technical difficulties that may cause interruptions to the Testnet. You understand that the Testnet may experience operational issues that lead to delays. You agree to accept the risk of any issues resulting from unanticipated or heightened technical difficulties, including those resulting from sophisticated attacks. You agree not to hold the Company accountable for any related losses. 18. You represent, warrant, and covenant that (i) you shall comply with all applicable Legal Requirements; (ii) your use of the Testnet is and will at all times comply with all Legal Requirements and these Terms; (iii) you will not use the Testnet, or permit the use of the foregoing by any third party, in any manner that is fraudulent, unlawful, deceptive or abusive (iv) you will not use the Testnet from a Restricted Territory or any jurisdiction that we have, in our sole discretion, or a relevant Regulatory Authority has determined is a jurisdiction where the use of the Testnet is prohibited under Legal Requirements; (v) you are not a Sanctions Target; and (vi) you will not use the Testnet to benefit or support any Restricted Territories or Sanctions Targets. For the purposes of these Terms: (1) “Legal Requirement” means applicable federal, state, and local laws, statutes, and regulations, and all applicable orders, judgments, decisions, rules, policies, opinions, attorney general opinions, or guidelines passed or issued by any Regulatory Authority or any competent court; Data Protection Laws; Sanctions; anti-corruption laws (including the Foreign Corrupt Practices Act and the UK Bribery Act); and all foreign laws regarding the same, relating to these Terms or otherwise applicable to either you or us, as the same may be amended and in effect from time to time; (2) “Restricted Territory” means a region, territory or country subject to Sanctions; (3) “Regulatory Authority” means any governmental, regulatory authority or law enforcement department, court, agency, commission, board, tribunal, crown corporation or other law, rule or regulation making entity (including any stock exchange or central bank) that either you or we submit to or are subject to the jurisdiction of in respect of these Terms, and any successor or replacement of any of the foregoing; (4) “Sanctions” means any Legal Requirement imposing sanctions, restrictions, or prohibitions on financial transactions or other business dealings that is administered or enforced by the U.S. Government (including the U.S. Department of Treasury’s Office of Foreign Assets Control, the U.S. Department of Commerce, or the U.S. Department of State and including designation as a “specially designated national” or blocked person), the United Nations Security Council, and all other relevant international sanctions authority, including any executive orders issued in relation to the imposition of sanctions; (5) “Sanctions Target” means any person that is: (A) included on any list of designated persons maintained by any Regulatory Authority pursuant to Sanctions, (B) organized, located or resident in a Restricted Territory, or (C) otherwise the target of any Sanctions such that a Person is prohibited from dealing with such person, including as a result of being owned or controlled by any person or persons described in the foregoing subsection (A) or (B). 19. For the avoidance of doubt, enforcement of the Terms is solely in our discretion and the absence of enforcement of these Terms in some instances does not constitute a waiver of our right to enforce the Terms in other instances. These Terms may be enforced by the Company or by any of its affiliates. In addition, these Terms do not create any private right of action on the part of any third party or any reasonable expectation or promise that the Testnet will not contain any content that is prohibited by the Terms. 2. [​](https://docs.arc.network/terms#testnet-access-prohibitions) Testnet Access Prohibitions ---------------------------------------------------------------------------------------------- You will only access the Testnet following the implementation instructions and other requirements specified in the documentation for the Testnet or as otherwise provided by the Company. By choosing to use the Testnet, you agree that you will not, and will not permit another person or entity to: 1. sell, rent, lease, sublicense, redistribute or syndicate access to the Testnet; 2. use the Testnet, or create a service that functions substantially the same as the Testnet, for the purpose of or with the effect of: (i) spoofing or simulating the Testnet; (ii) misrepresenting your or any third party’s association with the Company; (iii) misleading or confusing users about the origin, ownership, or operation of a product or service; or (iv) falsely implying sponsorship, endorsement, or certification by the Company; 3. infringe or violate the intellectual property rights or any other rights of anyone else (including the Company) or attempt to decompile, disassemble, or reverse engineer the Testnet; 4. violate any applicable law or regulation, including without limitation, and any applicable anti-money laundering laws, anti-terrorism laws, export control laws, end user restrictions, privacy laws or economic sanctions law/regulations, including those administered by the U.S. Department of Treasury’s Office of Foreign Assets Control; 5. encourage, facilitate, or promote illegal activity, or use the Testnet in a way that is dangerous, harmful, misleading, deceptive, threatening, harassing, defamatory, obscene, or otherwise objectionable, 6. commit a tort while using the Testnet; 7. use the Testnet in any manner that could interfere with, defraud, attack, disrupt, negatively affect, or inhibit other users from fully enjoying the Testnet, or that could damage, disable, overburden, or impair the functioning of the Testnet in any manner, including by (i) making any unsolicited offer or advertisement to another user of the Testnet; (ii) attempting to collect personal information about another user or third party without consent; or (iii) interfering with or disrupting any network, equipment, or server connected to or used to provide the Testnet, or violating any regulation, policy, or procedure of any such network, equipment, or server; 8. attempt to circumvent any content filtering techniques or security measures that the Company employs on the Testnet, or attempt to access any service or area of the Testnet that you are not authorized to access; 9. use any robot, spider, crawler, scraper, or other automated means or interface not provided by us, to access the Testnet or to extract data; 10. upload or introduce any malware, virus, Trojan horse, worm, logic bomb, drop-dead device, backdoor, shutdown mechanism or other harmful material into the Testnet; 11. provide false, inaccurate, or misleading information to the Company or otherwise on or in connection with your use of the Testnet; 12. post content or communications through your use of the Testnet that are, in our sole discretion, libelous, defamatory, profane, obscene, pornographic, sexually explicit, indecent, lewd, vulgar, suggestive, harassing, hateful, threatening, offensive, discriminatory, bigoted, abusive, inflammatory, fraudulent, deceptive or otherwise objectionable; 13. post content through your use of the Testnet containing unsolicited promotions, political campaigning, or commercial messages or any chain messages or user content designed to deceive or trick the user of the Testnet; or 14. encourage or induce any third party to engage in any of the activities prohibited under these Terms. Notwithstanding the foregoing, you may, solely for lawful, good-faith testing and evaluation of the Testnet, intentionally attack, disrupt, stress, reverse-engineer, or circumvent controls, provided that (i) such activity remains within the Testnet environment, avoids exfiltration of personal or confidential data, does not impair production or third-party systems, and is promptly disclosed to [security-ext@circle.com](mailto:security-ext@circle.com) and (ii) you cease such usage immediately upon the Company’s request. 3. [​](https://docs.arc.network/terms#connecting-digital-wallet) Connecting Digital Wallet ------------------------------------------------------------------------------------------ When using the Testnet, you may be required to connect your digital wallet through a compatible third-party software wallet. Third-party digital wallets constitute third-party services and the Company is not responsible for, does not endorse, shall not be held liable in connection with and does not make any warranties, whether express or implied, as to the third-party digital wallet used by you with the Testnet. Except where applicable to your use of certain Circle wallet products and services (which are subject to their own [terms and conditions](https://console.circle.com/legal/service-terms) ): (i) the Company never receives access to or control over your digital wallet; and (ii) therefore, you are solely responsible for (and we are not liable for any failure in) securing your digital wallet and credentials thereto, including seed phrases and private keys. You may disconnect your digital wallet from the Testnet at any time. 4. [​](https://docs.arc.network/terms#testnet-tokens) Testnet Tokens -------------------------------------------------------------------- 1. To use the Testnet, you will need to obtain Testnet USDC (“Testnet Tokens”), which are available at our Testnet [Faucet](https://faucet.circle.com/) , to cover computational resources required to perform a transaction on the Testnet. It is your responsibility to: (i) ensure that you have a sufficient balance of Testnet Tokens stored at your digital wallet address to complete any transaction on the Testnet before initiating such Testnet transaction; and (ii) confirm the amount of Testnet Tokens applicable to a particular Testnet transaction before authorizing that transaction. 2. Testnet Tokens are not and shall never convert, accrue or become Mainnet Tokens or any other tokens or digital assets. Any Testnet Tokens, associated transactions, and data do not have any monetary or intrinsic value. 3. Testnet Tokens are not redeemable, transferrable, or exchangeable for any real currency, digital asset, or financial instrument. Testnet Tokens are not transferable between users outside of the Testnet, and you may not attempt to sell, trade or transfer any Testnet Tokens outside of the Testnet or obtain any manner of credit using any Testnet Tokens. 4. The Company makes no commitment to maintain balances or transaction history on the Testnet. 5. [​](https://docs.arc.network/terms#no-agency) No Agency ---------------------------------------------------------- You will not make statements or represent yourself as an agent of the Company or mislead or deceive any third party with respect to your relationship with the Company. 6. [​](https://docs.arc.network/terms#no-financial-services) No Financial Services ---------------------------------------------------------------------------------- Participation in the Testnet does not create a financial account, custodial relationship, or investment relationship with the Company. The Company is not offering financial services or products through the Testnet. 7. [​](https://docs.arc.network/terms#submission-of-user-content) Submission of User Content -------------------------------------------------------------------------------------------- Certain offerings on the Testnet may allow for the submission of your own information (“User Content”), and except as expressly provided in these terms, the Company does not acquire any ownership of any intellectual property rights that you hold in the User Content that you submit using the Testnet. By submitting, posting, or displaying User Content to or from the Testnet, (a) you grant the Company a perpetual, irrevocable, worldwide, royalty-free, and non-exclusive license to use, reproduce, adapt, modify, translate, publish, publicly perform, publicly display and distribute such User Content to facilitate the Company’s provision of its services (including the Services) and the Testnet, in each case only in accordance with the [Privacy Policy](https://www.circle.com/legal/privacy-policy) and (b) you grant Testnet users a non-exclusive license to access and use that User Content as permitted by these Terms and the functionality of the Testnet. You represent that, before you submit User Content via the Testnet, you have the necessary rights (including any necessary rights acquired from related end users) to grant us the license. You are solely responsible for your User Content and the consequences of posting or publishing User Content. We are under no obligation to monitor, review, edit, or control User Content that you or other users post or publish, and will not be in any way responsible or liable for User Content. We may, however, at any time and without prior notice, screen, remove, edit, or block any User Content that in our sole judgment violates these Terms or is otherwise objectionable. You understand that when using the Testnet you will be exposed to User Content from a variety of sources and acknowledge that User Content may be inaccurate, offensive, indecent, or objectionable. YOU AGREE TO WAIVE, AND DO HEREBY WAIVE, ANY LEGAL OR EQUITABLE RIGHT OR REMEDY YOU HAVE OR MAY HAVE AGAINST US WITH RESPECT TO USER CONTENT. WE EXPRESSLY DISCLAIM ANY AND ALL LIABILITY IN CONNECTION WITH USER CONTENT. If notified by a user or content owner that User Content allegedly does not conform to these Terms, we may investigate (and cooperate with law enforcement in the investigation of) the allegation and determine in our sole discretion whether to remove the User Content, which we reserve the right to do at any time and without notice. YOU WAIVE AND HOLD HARMLESS THE COMPANY (AND ITS EMPLOYEES, DIRECTORS, AGENTS, AFFILIATES, AND REPRESENTATIVES) FROM ANY CLAIMS RESULTING FROM ANY ACTION TAKEN BY ANY OF THE FOREGOING PARTIES DURING, OR TAKEN AS A CONSEQUENCE OF, INVESTIGATIONS BY EITHER SUCH PARTIES OR LAW ENFORCEMENT AUTHORITIES. For clarity, we do not knowingly permit copyright-infringing activities on the Testnet. 8. [​](https://docs.arc.network/terms#digital-millennium-copyright-act) Digital Millennium Copyright Act -------------------------------------------------------------------------------------------------------- If you have an intellectual property rights related complaint about material posted on the Testnet, you may contact our designated agent at the following address: Circle Technology Services, LLC Attn: Digital Millennium Copyright Act One World Trade Center 87th floor, NY, NY 10007, USA Cc: legal@circle.com Any notice alleging that materials hosted by or distributed through the Testnet infringe intellectual property rights must include the following information: 1. an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other right being infringed; 2. a description of the copyright-protected work or other intellectual property right that you claim has been infringed; 3. a description of the material that you claim is infringing and where it is located on the Testnet; 4. your address, telephone number, and email address; 5. a statement by you that you have a good faith belief that the use of those materials on the Testnet is not authorized by the copyright owner, its agent, or Legal Requirement; and 6. a statement by you that the above information in your notice is accurate and that, under penalty of perjury, you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner’s behalf. To the extent within the Company’s control, the Company will endeavor to promptly remove from the Testnet users that are determined by the Company to be repeat infringers. A repeat infringer is a user who has been notified of infringing activity or has had User Content removed from the Testnet at least twice. 9. [​](https://docs.arc.network/terms#use-of-the-company-marks) Use of the Company Marks ---------------------------------------------------------------------------------------- You agree that you will not, nor will your affiliates, employees or agents, without prior written consent of the Company in each instance: (a) use in advertising, publicity, marketing or other promotional materials or activities, the name, logos or trademarks of the Company, its affiliates or their respective partners or employees; or (b) represent, directly or indirectly, that any product or any service provided by one party has been approved or endorsed by the Company. We may periodically make available certain “Arc” logos, trademarks, or other identifiers for your use as set forth in the Arc Brand Kit, currently available at [arc.network](https://arc.network/) , (“Arc Marks”). If we explicitly do so, you agree to use the Arc Marks subject to and in accordance with the Company’s then-current [Mark Policies](https://brand.circle.com/d/M9z54TaEwsWL/circle#/circle/policies) . We may limit or revoke your ability to use Arc Marks at any time. We may change Arc Marks from time to time. In the event that Arc Marks, Arc Brand Kit or Arc [Mark Policies](https://brand.circle.com/d/M9z54TaEwsWL/circle#/circle/policies) are changed, you agree to (i) use the then current version of the Arc Marks and (ii) use Arc Marks consistent with the then-current Arc Brand Kit and Mark Policies. All rights not provided in the Arc Brand Kit or [Mark Policies](https://brand.circle.com/d/M9z54TaEwsWL/circle#/circle/policies) are expressly reserved by us. 10. [​](https://docs.arc.network/terms#ownership-feedback) Ownership; Feedback ----------------------------------------------------------------------------- The Company grants you a non-exclusive, limited, revocable, terminable, personal, non-assignable, and non sublicensable license to participate in the Testnet, in strict accordance with these Terms. This license shall automatically expire upon the termination of your participation in the Testnet. You acknowledge and agree that as between you and the Company, the Company owns all right, title and interest in and to the Testnet, Arc Marks, and any Arc services (and any derivative works or enhancements thereof), including all intellectual property rights therein. You agree not to do anything inconsistent with such ownership. Any rights not expressly granted herein are withheld. If you submit any comment or idea about improvements to the Testnet (“Feedback”) to the Company, you acknowledge and agree that your submission was voluntary, unsolicited by the Company, and delivered to the Company without any restrictions or confidentiality obligations on the Company’s use of the Feedback. You hereby assign all right, title, and interest in and to any Feedback that you submit or provide to the Company, whether or not the submitted Feedback is protectable by intellectual property laws of your or the Company’s related jurisdiction. You agree that the Company has no fiduciary or any other obligation to you in connection with any Feedback that you submit or provide to the Company, and that the Company is free to use, copy, display, perform, distribute, modify and re-format such Feedback in any manner that the Company may determine, without any attribution or compensation to you. 11. [​](https://docs.arc.network/terms#termination) Termination -------------------------------------------------------------- We may terminate these Terms or suspend or terminate your use of the Testnet (or any portion thereof) at any time for any reason. We may add or remove, suspend, stop, delete, discontinue or impose conditions on the Testnet or any feature or aspect of the Testnet. If these Terms or your use of the Testnet is terminated or suspended for any reason or no reason: (a) the license and any other rights granted under these Terms and any other applicable terms will end, (b) we may (but have no obligation to other than to the extent required by applicable Legal Requirements) delete your information stored on our servers, and (c) the Company shall not be liable to you or any third party for compensation, reimbursement, or damages for any termination or suspension of your use of the Testnet or for deletion of your information. If your use of the Testnet is terminated or suspended, you agree to: (i) continue to be bound by these Terms to the extent such provisions survive termination; and (ii) immediately stop using the Testnet. 12. [​](https://docs.arc.network/terms#no-warranties) No Warranties ------------------------------------------------------------------ THE TESTNET IS PROVIDED “AS IS” AND “AS AVAILABLE” WITHOUT REPRESENTATION, WARRANTY OR CONDITION OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY. WITHOUT LIMITING THE FOREGOING, THE COMPANY SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THE COMPANY DOES NOT WARRANT OR GUARANTEE THAT THE TESTNET: (A) IS ACCURATE, RELIABLE OR CORRECT; (B) WILL MEET YOUR REQUIREMENTS; OR (C) WILL BE AVAILABLE AT ANY PARTICULAR TIME OR LOCATION, WILL BE UNINTERRUPTED, WILL BE ERROR-FREE, OR WITHOUT DEFECT OR SECURE. THE COMPANY FURTHER DOES NOT WARRANT OR GUARANTEE THAT ANY DEFECTS OR ERRORS WILL BE CORRECTED; OR THAT THE TESTNET IS FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS. ANY DATA DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE TESTNET ARE DOWNLOADED AT YOUR OWN RISK AND YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR PROPERTY OR LOSS OF DATA THAT RESULTS FROM SUCH DOWNLOAD. The Company does not warrant, endorse, guarantee, or assume responsibility for any products or services advertised or offered by a third party. You also understand and agree that the Company does not control any products or services offered by third parties using the Testnet. The Company is not liable for any losses or issues that may arise from such third-party products or services, including failure to comply with applicable Legal Requirements, the quality and delivery of such products and services, or your satisfaction with any products or services. If you are not satisfied with any goods or services made available by a third party on the Testnet, you must handle those issues directly with such third-party. 13. [​](https://docs.arc.network/terms#limitation-of-liability) Limitation of Liability -------------------------------------------------------------------------------------- TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL THE COMPANY BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR EXEMPLARY DAMAGES, INCLUDING DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA, OR OTHER INTANGIBLE LOSSES, THAT RESULT FROM THE USE OF, INABILITY TO USE, OR UNAVAILABILITY OF THE TESTNET. IN ALL CASES, THE COMPANY WILL NOT BE LIABLE FOR ANY LOSS OR DAMAGE THAT IS NOT REASONABLY FORESEEABLE. UNDER NO CIRCUMSTANCES WILL THE COMPANY BE RESPONSIBLE FOR ANY DAMAGE, LOSS, OR INJURY RESULTING FROM HACKING, TAMPERING, OR OTHER UNAUTHORIZED ACCESS OR USE OF THE TESTNET, OR THE INFORMATION CONTAINED THEREIN. TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, THE COMPANY ASSUMES NO LIABILITY OR RESPONSIBILITY FOR ANY (I) ERRORS, MISTAKES, OR INACCURACIES OF THE TESTNET; (II) PERSONAL INJURY OR PROPERTY DAMAGE, OF ANY NATURE WHATSOEVER, RESULTING FROM YOUR ACCESS TO OR USE OF THE TESTNET; (III) ANY UNAUTHORIZED ACCESS TO OR USE OF OUR SECURE SERVERS AND/OR ANY AND ALL PERSONAL INFORMATION STORED THEREIN; (IV) ANY INTERRUPTION OR CESSATION OF TRANSMISSION TO OR FROM THE TESTNET; (V) ANY BUGS, VIRUSES, TROJAN HORSES, OR THE LIKE THAT MAY BE TRANSMITTED TO OR THROUGH THE TESTNET BY ANY THIRD PARTY; (VI) ANY ERRORS OR OMISSIONS IN ANY DATA OR FOR ANY LOSS OR DAMAGE INCURRED AS A RESULT OF THE USE OF ANY DATA POSTED, EMAILED, TRANSMITTED, OR OTHERWISE MADE AVAILABLE THROUGH THE TESTNET. TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, THE TOTAL LIABILITY OF THE COMPANY IS LIMITED TO $100. THIS LIMITATION OF LIABILITY SECTION APPLIES WHETHER THE ALLEGED LIABILITY IS BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY, OR ANY OTHER BASIS, EVEN IF THE COMPANY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE FOREGOING LIMITATION OF LIABILITY SHALL APPLY TO THE FULLEST EXTENT PERMITTED BY LAW IN THE APPLICABLE JURISDICTION. 14. [​](https://docs.arc.network/terms#indemnity) Indemnity ---------------------------------------------------------- You will indemnify, defend, and hold us (and our employees, directors, agents, affiliates and representatives) harmless from and against any and all claims, costs, losses, damages, judgments, tax assessments, penalties, interest, and expenses (including reasonable attorneys’ fees) arising out of any claim, action, audit, investigation, inquiry, or other proceeding instituted by a person or entity that arises out of or relates to: (a) any actual or alleged breach of your representations, warranties, or obligations set forth in these Terms, including any violation of our policies; (b) your wrongful or improper use of the Testnet; (c) your violation of any third-party right, including any right of privacy, publicity rights or intellectual property rights; (d) your violation of any Legal Requirement of the United States or any other country; (e) any other party’s access and/or use of the Testnet with your unique name, password or other appropriate security code; or (f) your willful misconduct, gross negligence or fraud. 15. [​](https://docs.arc.network/terms#modification-of-terms) Modification of Terms ---------------------------------------------------------------------------------- We may amend these Terms or modify the Testnet, including any applicable accompanying documentation and guidelines, at any time with notice that we deem to be reasonable in the circumstances, by posting the revised version on our website (each a “Revised Version”). We will update the “Last Updated” date at the top of the Terms to reflect the Revised Version. The Revised Version will be effective immediately as of the time it is posted, but will not apply retroactively. Your continued use of and access to the Testnet after the posting of a Revised Version constitutes your acceptance of such Revised Version. Any Dispute (as defined in Section 14) that arose before the changes will be governed by the terms of service in place when the Dispute arose. You may not amend these Terms without our prior written consent. If you are a user from anywhere in the world, you are contracting with the Company. 16. [​](https://docs.arc.network/terms#dispute-resolution-binding-individual-arbitration-class-action-waiver) Dispute Resolution; Binding Individual Arbitration; Class Action Waiver ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ “Disputes” are defined as any claim, controversy, or dispute between you and the Company, its suppliers, service providers or licensors (or their respective affiliates, agents, directors or employees), whether arising before or during the effective period of these Terms, and including any claim, controversy, or dispute based on any conduct of you or the Company that occurred before the effective date of these Terms, including any claims arising from or relating in any way to these Terms or any matter relating to the Testnet. 1. **General** You and the Company agree that any and all Disputes, except those that are resolved informally or brought in a small claims court, will be arbitrated by a neutral arbitrator who has the power to award the same individual damages and individual relief that a court can. ANY ARBITRATION UNDER THESE GENERAL TERMS WILL ONLY BE ON AN INDIVIDUAL BASIS; CLASS ARBITRATIONS, CLASS ACTIONS, REPRESENTATIVE ACTIONS, AND CONSOLIDATION WITH OTHER ARBITRATIONS ARE NOT PERMITTED. YOU WAIVE ANY RIGHT TO HAVE YOUR CASE DECIDED BY A JURY AND YOU WAIVE ANY RIGHT TO PARTICIPATE IN A CLASS ACTION AGAINST THE COMPANY. If any provision of this arbitration agreement is found unenforceable, the unenforceable provision will be severed, and the remaining arbitration terms will be enforced (but in no case will there be a class or representative arbitration). 2. **Pre-Filing Requirement to Attempt to Resolve Disputes** Before an arbitration is commenced, you or the Company agree to attempt to avoid the costs of formal dispute resolution by giving each other a full and fair opportunity to address and resolve a Dispute informally. Both parties recognize that this is an important requirement, and that breach of this requirement would be a material breach of the Terms. To provide this opportunity, before commencing any arbitration or suit, each party agrees to send to the other party a written Notice (“Notice”). Any Notice to the Company should be sent by email to [arbitration@circle.com](mailto:arbitration@circle.com) or by mail to Circle Technology Services, LLC, Attn: Arbitration Provision, One World Trade Center, 87th floor, NY, NY 10007, USA. Any Notice sent to you will be sent to the address on file for your account. The Notice must: (i) include your name and account number; (ii) provide detailed information sufficient to evaluate the merits of the claiming party’s individualized claim and for the other party to determine if an amicable resolution is possible; and (iii) set forth the specific relief sought, including whatever amount of money is demanded and the means by which the demanding party calculated the claimed damages. Both parties agree that they will attempt to resolve a dispute through an informal negotiation within sixty (60) days from the date the Notice is sent. After that sixty (60) day period and not before, either party may commence arbitration. Each party agrees that state or federal courts in New York, New York, USA referenced below, may enter injunctive relief to enforce the pre-filing requirements of this paragraph, including an injunction to stay an arbitration that has been commenced in violation of this paragraph. 3. **Scope of Arbitration** If we are not able to resolve the Dispute by informal negotiation or, as provided below, in a small claims court, all Disputes will be resolved finally and exclusively by binding individual arbitration with a single arbitrator (the “Arbitrator”) administered by JAMS Mediation, Arbitration, ADR services (“JAMS”) in accordance with The Comprehensive Arbitration Rules and Procedures of JAMS (available from JAMS on its website at [www.jams.com](http://www.jams.com/) ). You and the Company will have the right to file early or summary dispositive motions and to request that the relevant expedited procedures apply regardless of the claim amount. An arbitration will be conducted by a single, neutral arbitrator and shall take place in New York, New York, USA unless otherwise mutually agreed by the parties. Except as set forth above, the Arbitrator shall be responsible for determining all threshold arbitrability issues, including issues relating to whether the Terms and/or any Additional Terms (or any aspect thereof) are enforceable, unconscionable or illusory and any defense to arbitration, including waiver, delay, laches, or estoppel. 4. **Small Claims Court** Subject to applicable jurisdictional requirements, either party may elect to pursue a Dispute in a local small-claims court rather than through arbitration so long as the matter remains in small claims court and proceeds only on an individual basis. If a party has already submitted an arbitration demand to the JAMS, the other party may, in its sole discretion, inform JAMS that it chooses to have the Dispute heard in small claims court. At that time, JAMS will close the arbitration and the Dispute will be heard in the appropriate small claims court, with no fees due from the arbitration respondent. 5. **Arbitration Procedures** The Federal Arbitration Act, 9 U.S.C. §§ 1-16, including its procedural provisions, fully applies. Any arbitration hearing will occur in New York, New York, at another mutually agreeable location or, if both parties agree, by telephone or videoconference. Any arbitration shall be conducted in English. The Arbitrator’s award will be binding on the parties and may be entered as a judgment in any court of competent jurisdiction. The Company values your privacy, particularly with respect to your financial transactions and data. Each of the parties shall maintain the confidential nature of the arbitration and shall not (without the prior written consent of the other party) disclose to any third party the fact, existence, content, award, or other result of the arbitration, except as may be necessary to enforce, enter, or challenge such award in a court of competent jurisdiction or as otherwise required by applicable Legal Requirements. While an arbitrator may award declaratory or injunctive relief, the Arbitrator may do so only with respect to the individual party seeking relief and only to the extent necessary to provide relief warranted by the individual party’s claim. The Arbitrator’s decision and judgment thereon will not have a precedential or collateral estoppel effect. 6. **Arbitration Fees** In accordance with JAMS, the party initiating the arbitration (either you or us) is responsible for paying the applicable filing fee. For purposes of this arbitration provision, references to you and the Company also include respective subsidiaries, affiliates, agents, employees, predecessors, successors and assigns as well as authorized users or beneficiaries of the Services. 7. **Opt Out** You may reject this provision, in which case only a court may be used to resolve any Dispute. To reject this provision, you must send us an opt-out notice (the “Opt Out”) within thirty (30) days after you access the Testnet or we first provide you with the right to reject this provision. The Opt Out may be mailed to Circle Technology Services, LLC, Attn: Arbitration Provision, One World Trade Center, 87th floor, NY, NY 10007, USA. Alternatively, you may send an email with the subject line “Opt Out of Arbitration” to [customer-support@circle.com](mailto:customer-support@circle.com) . Any Opt Out notice must include your name, address, phone number and the email address(es) you used to sign up and use the Services. You must send such a notice in order to opt out of this provision. Opting out will not affect any other aspect of the Terms or the Testnet and will have no effect on any other or future agreements you may reach to arbitrate with us. 8. **Court Proceedings** Subject to and without waiver of the arbitration provisions above, you agree that any judicial proceedings (other than small claims actions as discussed above) will be brought in and you hereby consent to the exclusive jurisdiction and venue in the state or federal courts in New York, New York. 17. [​](https://docs.arc.network/terms#governing-law) Governing Law ------------------------------------------------------------------ These Terms are governed by Delaware law without regard to its choice of law or conflicts of law principles and/or applicable the federal law of the United States. Any arbitration related to any Dispute will be governed by the Federal Arbitration Act, as set forth above. 18. [​](https://docs.arc.network/terms#limitation-on-time-to-initiate-a-dispute) Limitation on Time to Initiate a Dispute ------------------------------------------------------------------------------------------------------------------------ Any action or proceeding by you relating to any Dispute must commence within one (1) year after the cause of action accrues. 19. [​](https://docs.arc.network/terms#assignment-change-of-control) Assignment; Change of Control ------------------------------------------------------------------------------------------------- These Terms and any rights and licenses granted hereunder, may not be transferred or assigned by you and any attempted transfer or assignment will be null and void. We may assign these Terms without your consent, including to any Company affiliate or subsidiary. 20. [​](https://docs.arc.network/terms#other-provisions) Other Provisions ------------------------------------------------------------------------ These Terms and any other applicable terms or policies, are a complete statement of the agreement between you and the Company regarding the Testnet. If any provision of these Terms is invalid or unenforceable under applicable law, then it will be changed and interpreted to accomplish the objectives of such provision to the greatest extent possible under applicable law, and the remaining provisions will continue in full force and effect. These Terms do not limit any rights that the Company may have under trade secret, copyright, patent, or other laws. No waiver of any term of these Terms shall be deemed a further or continuing waiver of such term or any other term. From time to time, we may request you to certify, in writing, that you are in compliance with these Terms and all other applicable terms and policies, and the purpose or use of the Testnet and related data that you have access to, and that each such purpose or use complies with these Terms and all other applicable terms and policies. All such certifications and attestations must be provided by an authorized representative of yours in writing. For purposes of interpreting this Agreement, unless otherwise specifically stated: (a) the singular includes the plural, and the plural includes the singular; (b) the words “herein”, “hereunder” and “hereof” and other words of similar import refer to this Agreement as a whole and not to any particular section or paragraph; (c) the words “include” and “including” will not be construed as terms of limitation, and will therefore mean “including but not limited to” and “including without limitation”; (d) the words “writing” or “written” mean preserved or presented in retrievable or reproducible form, whether electronic (including email but excluding voice mail) or hard copy; (e) the captions and section and paragraph headings used in this Agreement are inserted for convenience only and will not affect the meaning or interpretation of this Agreement; and (f) the references herein to the parties will refer to their permitted successors and assigns. 21. [​](https://docs.arc.network/terms#survival) Survival -------------------------------------------------------- The following sections of these Terms survive and remain in effect in accordance with their terms upon termination of these Terms: 1(e) through 1(s) (inclusive), 5 (No Agency), 7 (Submission of User Content), 8 (Digital Millennium Copyright Act), 10 (Ownership; Feedback), 11 (Termination), 12 (No Warranties), 13 (Limitation of Liability), 14 (Indemnity), 15 (Modification of Terms), 16 (Dispute Resolution; Binding Individual Arbitration; Class Action Waiver), 17 (Governing Law), 18 (Limitation on Time to Initiate a Dispute), 19 (Assignment; Change of Control), 20 (Other Provisions) and 21 (Survival). Was this page helpful? YesNo ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Bridge USDC to Arc - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Bridge USDC to Arc [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [3.2. Run the script](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#3-2-run-the-script) * [3.3. Verify the transfer](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#3-3-verify-the-transfer) * [Summary](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#summary) [Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol) is a permissionless onchain utility that facilitates USDC transfers securely between supported blockchains via native burning and minting. For more info, visit the [CCTP](https://developers.circle.com/cctp) docs. This tutorial walks you through bridging USDC to Arc Testnet with [Bridge Kit](https://developers.circle.com/bridge-kit) . Select the tab that matches your adapter setup. * Circle Wallets * Solana * Viem [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#prerequisites) Prerequisites --------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. Installed [Node.js v22+](https://nodejs.org/) 2. A [Circle Developer Console](https://console.circle.com/) account 3. An API key created in the Console: **Keys → Create a key → API key → Standard Key** 4. Your [Entity Secret registered](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-1-set-up-your-project) Step 1. Set up your project ------------------------------------------------------------------------------------------------------------------------ In this step, you prepare your project and environment. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-1-create-the-project-and-install-dependencies) 1.1. Create the project and install dependencies Create a new project directory and install Bridge Kit with the Circle Wallets adapter: Shell mkdir crosschain-transfer && cd crosschain-transfer npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" npm install @circle-fin/bridge-kit @circle-fin/adapter-circle-wallets npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-3-set-environment-variables) 1.3. Set environment variables Create a `.env` file in the project directory: .env CIRCLE_API_KEY=YOUR_API_KEY CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET EVM_WALLET_ADDRESS=YOUR_EVM_WALLET_ADDRESS SOLANA_WALLET_ADDRESS=YOUR_SOLANA_WALLET_ADDRESS * `CIRCLE_API_KEY` is your Circle Developer API key for the Circle Wallets adapter. * `CIRCLE_ENTITY_SECRET` is your registered entity secret used to authorize developer-controlled wallet operations. * `EVM_WALLET_ADDRESS` is your Arc Testnet or EVM developer-controlled wallet address. * `SOLANA_WALLET_ADDRESS` is your Solana Devnet developer-controlled wallet address. The `npm run start` command loads these variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-2-set-up-your-wallets) Step 2. Set up your wallets ------------------------------------------------------------------------------------------------------------------------ In this step, you create developer-controlled wallets on Arc Testnet and the source chain, then fund them for the bridge flow. If you already have funded wallets on Arc Testnet and your source chain, skip to [Step 3](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-3-bridge-usdc) . ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#2-1-create-wallets) 2.1. Create wallets Install the [Circle Dev-Controlled Wallets SDK](https://www.npmjs.com/package/@circle-fin/developer-controlled-wallets) : npm install @circle-fin/developer-controlled-wallets Then create wallets on Arc Testnet and your source chain, the example shows how to create wallets on Arc Testnet and Solana Devnet: import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const client = initiateDeveloperControlledWalletsClient({ apiKey: "", entitySecret: "", }); const walletSetResponse = await client.createWalletSet({ name: "Bridge Wallets", }); /* * Testnet blockchains: * ETH-SEPOLIA | AVAX-FUJI | MATIC-AMOY | SOL-DEVNET | ARB-SEPOLIA * UNI-SEPOLIA | BASE-SEPOLIA | OP-SEPOLIA | ARC-TESTNET | MONAD-TESTNET */ const walletsResponse = await client.createWallets({ blockchains: ["ARC-TESTNET", "SOL-DEVNET"], count: 1, walletSetId: walletSetResponse.data?.walletSet?.id ?? "", }); If you’re calling the API directly, you’ll need to make two requests: one to create the wallet set and one to create the wallet. Be sure to replace the Entity Secret ciphertext and the idempotency key in your request. If you’re using the SDKs, this is handled automatically for you. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#2-2-fund-your-wallets) 2.2. Fund your wallets Obtain testnet USDC from the [Circle Faucet](https://faucet.circle.com/) and native tokens from the [Console Faucet](https://console.circle.com/faucet) to pay gas fees on both the source chain and Arc Testnet. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#2-3-check-wallet-balances) 2.3. Check wallet balances You can check wallet balances from the [Developer Console](https://console.circle.com/wallets/dev/wallets) or programmatically: Node.js cURL const response = await client.getWalletTokenBalance({ id: "", }); [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-3-bridge-usdc) Step 3. Bridge USDC -------------------------------------------------------------------------------------------------------- In this step, you set up your script, execute the bridge transfer, and check the result. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#3-1-create-the-script) 3.1. Create the script Create an `index.ts` file in the project directory and add the following code. Pick the source chain that matches the wallet you funded. Each example uses the exact Bridge Kit chain identifier accepted by the SDK. [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#prerequisites-2) Prerequisites ----------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. Installed [Node.js v22+](https://nodejs.org/) 2. A Solana Devnet wallet 3. An [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) EVM wallet [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-1-set-up-your-project-2) Step 1. Set up your project -------------------------------------------------------------------------------------------------------------------------- In this step, you prepare your project and environment. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-1-create-the-project-and-install-dependencies-2) 1.1. Create the project and install dependencies Create a new project directory and install Bridge Kit with the Solana and Viem adapters: Shell mkdir crosschain-transfer && cd crosschain-transfer npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" npm install @circle-fin/bridge-kit @circle-fin/adapter-solana-kit @circle-fin/adapter-viem-v2 npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-2-configure-typescript-optional-2) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-3-set-environment-variables-2) 1.3. Set environment variables Create a `.env` file in the project directory: .env SOLANA_PRIVATE_KEY=YOUR_SOLANA_PRIVATE_KEY EVM_PRIVATE_KEY=0xYOUR_EVM_PRIVATE_KEY * `SOLANA_PRIVATE_KEY` is the private key for the Solana Devnet wallet that holds the source USDC. * `EVM_PRIVATE_KEY` is the `0x`\-prefixed private key for the Arc Testnet wallet that receives the bridged USDC. The `npm run start` command loads these variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-2-prepare-your-wallets) Step 2. Prepare your wallets -------------------------------------------------------------------------------------------------------------------------- In this step, you fund both wallets used in the bridge flow. If you already have a funded Solana wallet and a funded Arc Testnet wallet, skip ahead to the bridge step. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#2-1-fund-your-solana-wallet) 2.1. Fund your Solana wallet Obtain testnet USDC from the [Circle Faucet](https://faucet.circle.com/) and SOL from the [Solana Faucet](https://faucet.solana.com/) so your source wallet can pay for the bridge steps on Solana Devnet. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#2-2-fund-your-arc-testnet-wallet) 2.2. Fund your Arc testnet wallet Obtain Arc Testnet USDC from the [Console Faucet](https://console.circle.com/faucet) so the destination wallet can pay for the mint step on Arc Testnet. [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-3-bridge-usdc-2) Step 3. Bridge USDC ---------------------------------------------------------------------------------------------------------- In this step, you set up your script, execute the bridge transfer, and check the result. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#3-1-create-the-script-2) 3.1. Create the script Create an `index.ts` file in the project directory and add the following code. This example bridges USDC from `Solana_Devnet` to `Arc_Testnet`.For other supported chains, refer to the [SDK blockchain reference](https://docs.arc.network/app-kit/references/sdk-reference#blockchain) . TypeScript // Import Bridge Kit, the Solana adapter, and the Viem adapter import { BridgeKit } from "@circle-fin/bridge-kit"; import { createSolanaKitAdapterFromPrivateKey } from "@circle-fin/adapter-solana-kit"; import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { inspect } from "util"; // Initialize the SDK const kit = new BridgeKit(); const bridgeUSDC = async () => { try { const solanaAdapter = createSolanaKitAdapterFromPrivateKey({ privateKey: process.env.SOLANA_PRIVATE_KEY as string, }); const evmAdapter = createViemAdapterFromPrivateKey({ privateKey: process.env.EVM_PRIVATE_KEY as string, }); console.log("---------------Starting Bridging---------------"); const result = await kit.bridge({ from: { adapter: solanaAdapter, chain: "Solana_Devnet" }, to: { adapter: evmAdapter, chain: "Arc_Testnet" }, amount: "1.00", }); console.log("RESULT", inspect(result, false, null, true)); } catch (err) { console.log("ERROR", inspect(err, false, null, true)); } }; void bridgeUSDC(); [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#prerequisites-3) Prerequisites ----------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. Installed [Node.js v22+](https://nodejs.org/) 2. An EVM wallet such as [MetaMask](https://metamask.io/) 3. The source EVM testnet added to your wallet 4. The [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) network added to your wallet [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-1-set-up-your-project-3) Step 1. Set up your project -------------------------------------------------------------------------------------------------------------------------- In this step, you prepare your project and environment. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-1-create-the-project-and-install-dependencies-3) 1.1. Create the project and install dependencies Create a new project directory and install Bridge Kit with the Viem adapter: Shell mkdir crosschain-transfer && cd crosschain-transfer npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" npm install @circle-fin/bridge-kit @circle-fin/adapter-viem-v2 npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-2-configure-typescript-optional-3) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#1-3-set-environment-variables-3) 1.3. Set environment variables Create a `.env` file in the project directory: .env PRIVATE_KEY=0xYOUR_PRIVATE_KEY * `PRIVATE_KEY` is the `0x`\-prefixed private key for the EVM wallet that holds USDC on the source chain and can receive bridged USDC on Arc Testnet. The `npm run start` command loads these variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-2-prepare-your-wallets-2) Step 2. Prepare your wallets ---------------------------------------------------------------------------------------------------------------------------- In this step, you fund the source wallet and the Arc Testnet destination wallet used in the bridge flow. If you already have both wallets funded, skip ahead to the bridge step. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#2-1-fund-the-source-wallet) 2.1. Fund the source wallet Obtain testnet USDC from the [Circle Faucet](https://faucet.circle.com/) and the source chain’s native token from a public faucet so you can approve and burn USDC on the source chain. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#2-2-fund-your-arc-testnet-wallet-2) 2.2. Fund your Arc testnet wallet Obtain Arc Testnet USDC from the [Console Faucet](https://console.circle.com/faucet) so the destination wallet can pay for the mint step. [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#step-3-bridge-usdc-3) Step 3. Bridge USDC ---------------------------------------------------------------------------------------------------------- In this step, you set up your script, execute the bridge transfer, and check the result. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#3-1-create-the-script-3) 3.1. Create the script Create an `index.ts` file in the project directory and add the following code. Pick the source chain that matches the EVM wallet you funded. Each example uses the exact Bridge Kit chain identifier accepted by the SDK.For other supported chains, refer to the [SDK blockchain reference](https://docs.arc.network/app-kit/references/sdk-reference#blockchain) . ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#3-2-run-the-script) 3.2. Run the script Save the `index.ts` file and run the script in your terminal: npm run start For blockchains other than Arc, you will need native tokens to pay for gas. The **approve** and **burn** steps require gas fees in the native token of the source chain, while the **mint** step requires gas fees in the native token of the destination chain. ### [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#3-3-verify-the-transfer) 3.3. Verify the transfer After the script finishes, locate the returned `steps` array in the terminal output. Each transaction step includes an `explorerUrl` field. Use that URL to verify that the USDC amount matches the amount you transferred. The following example shows how all four steps (Approve, Burn, Fetch Attestation, Mint) might look like in the terminal output. The values shown are for demonstration purposes only and don’t represent a real transaction: Approve Burn Fetch Attestation Mint { name: 'approve', state: 'success', txHash: '0x809cd6678785c3cb48d73a8e35e5ef8fc21c1b1e22df767860bc30bd882fb470', data: { txHash: '0x809cd6678785c3cb48d73a8e35e5ef8fc21c1b1e22df767860bc30bd882fb470', status: 'success', cumulativeGasUsed: 429183n, gasUsed: 38596n, blockNumber: 20523074n, blockHash: '0x5d81b5abab77f19fb3e70df620276fe9b4be68172482afa0188296ead97c3033', transactionIndex: 5, effectiveGasPrice: 162000000000n }, explorerUrl: 'https://testnet.arcscan.app/tx/0x809cd6678785c3cb48d73a8e35e5ef8fc21c1b1e22df767860bc30bd882fb470' } * * * [​](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc#summary) Summary --------------------------------------------------------------------------------- After completing this tutorial, you’ve successfully: * Set up a Bridge Kit workflow for Circle Wallets, Viem, or Solana adapters * Funded the source and destination wallets needed for the bridge flow * Bridged USDC to Arc Testnet Was this page helpful? YesNo [Deploy contracts](https://docs.arc.network/arc/tutorials/deploy-contracts) [Transfer USDC or EURC](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Monitor contract events - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/monitor-contract-events#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Monitor contract events [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/arc/tutorials/monitor-contract-events#prerequisites) * [Step 1. Update your project](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-1-update-your-project) * [Step 2. Set up your webhook](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-2-set-up-your-webhook) * [Step 3. Register your webhook in Console](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-3-register-your-webhook-in-console) * [Step 4. Import a contract (optional)](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-4-import-a-contract-optional) * [Step 5. Create an event monitor](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-5-create-an-event-monitor) * [Step 6. Receive webhook notifications](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-6-receive-webhook-notifications) * [Step 7. Retrieve event logs](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-7-retrieve-event-logs) * [Summary](https://docs.arc.network/arc/tutorials/monitor-contract-events#summary) Track contract events and get event logs with the Circle Contracts API. [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#prerequisites) Prerequisites -------------------------------------------------------------------------------------------------- You need a deployed contract to monitor. If you completed the [Deploy contracts](https://docs.arc.network/arc/tutorials/deploy-contracts) tutorial, you can continue with that contract. If your contract was deployed elsewhere, import it in [Step 3](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-3-import-a-contract-optional) . [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-1-update-your-project) Step 1. Update your project ----------------------------------------------------------------------------------------------------------------------------- If you haven’t already, add run scripts for monitoring contract events to your `package.json`: npm pkg set scripts.webhook="tsx webhook-receiver.ts" npm pkg set scripts.import-contract="tsx --env-file=.env import-contract.ts" npm pkg set scripts.create-monitor="tsx --env-file=.env create-monitor.ts" npm pkg set scripts.get-event-logs="tsx --env-file=.env get-event-logs.ts" If you completed the Deploy contracts tutorial, your project already has the required SDKs installed. The npm scripts previously listed work with your existing setup. [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-2-set-up-your-webhook) Step 2. Set up your webhook ----------------------------------------------------------------------------------------------------------------------------- Event monitors send real-time updates to your webhook endpoint when events happen. * webhook.site * ngrok 1. Visit [webhook.site](https://webhook.site/) 2. Copy your unique webhook URL (for example, `https://webhook.site/your-uuid`) 1. Install `ngrok` from [ngrok.com](https://ngrok.com/) 2. Create a webhook receiver script: webhook-receiver.ts webhook\_receiver.py import express, { Request, Response } from "express"; const app = express(); app.use(express.json()); app.post("/webhook", (req: Request, res: Response) => { console.log("Received webhook:"); console.log(JSON.stringify(req.body, null, 2)); res.status(200).json({ received: true }); }); const PORT = 3000; app.listen(PORT, () => { console.log(`Webhook receiver listening on port ${PORT}`); console.log(`Endpoint: http://localhost:${PORT}/webhook`); }); 3. Start the webhook receiver: Node.js Python npm run webhook 4. In a separate terminal, start `ngrok`: ngrok http 3000 5. Copy the HTTPS forwarding URL (for example, `https://abc123.ngrok-free.app/webhook`) If using `ngrok` for local testing, you can optionally set `WEBHOOK_URL` in your `.env` file to store your `ngrok` forwarding URL. [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-3-register-your-webhook-in-console) Step 3. Register your webhook in Console ------------------------------------------------------------------------------------------------------------------------------------------------------- Register your webhook URL in the Developer Console: 1. Go to [Developer Console](https://console.circle.com/) 2. Navigate to **Webhooks** (left sidebar) 3. Click **Add a webhook** 4. Enter your webhook URL (from Step 1) and create the webhook Register your webhook before creating event monitors. This allows Circle to send notifications to your endpoint. [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-4-import-a-contract-optional) Step 4. Import a contract (optional) --------------------------------------------------------------------------------------------------------------------------------------------- If your contract was deployed elsewhere and is not yet available in the Developer Console, import it first. If you deployed a contract using Circle Contracts, including the [Deploy contracts](https://docs.arc.network/arc/tutorials/deploy-contracts) tutorial, skip this step. Your contract is already available in the Console. import-contract.ts import\_contract.py import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const contractClient = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); async function importContract() { try { const response = await contractClient.importContract({ blockchain: "ARC-TESTNET", address: process.env.CONTRACT_ADDRESS, name: "MyContract", }); console.log(JSON.stringify(response.data, null, 2)); } catch (error) { console.error("Error importing contract:", error.message); throw error; } } importContract(); **Run the script:** Node.js Python npm run import-contract If the contract is already imported, you’ll see an error: `contract already exists`. This means the contract is already available in the Console and you can proceed to create an event monitor. [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-5-create-an-event-monitor) Step 5. Create an event monitor ------------------------------------------------------------------------------------------------------------------------------------- Event monitors track specific contract events. They send updates to your webhook endpoint. This example monitors `Transfer` events: create-monitor.ts create\_monitor.py import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const contractClient = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); async function createEventMonitor() { try { const response = await contractClient.createEventMonitor({ blockchain: "ARC-TESTNET", contractAddress: process.env.CONTRACT_ADDRESS, eventSignature: "Transfer(address,address,uint256)", }); console.log(JSON.stringify(response.data, null, 2)); } catch (error) { console.error("Error creating event monitor:", error.message); throw error; } } createEventMonitor(); **Run the script:** Node.js Python npm run create-monitor **Response:** { "eventMonitor": { "id": "019bf984-b4da-7026-a3d2-674ce371a933", "contractName": "TestERC20Token", "contractId": "019bf8be-7be5-7a3e-89cc-05bcd7413f20", "contractAddress": "0x281156899e5bd6fecf1c0831ee24894eeeaea2f8", "blockchain": "ARC-TESTNET", "eventSignature": "Transfer(address,address,uint256)", "eventSignatureHash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "isEnabled": true, "createDate": "2026-01-26T08:56:22.490638Z", "updateDate": "2026-01-26T08:56:22.490638Z" } } [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-6-receive-webhook-notifications) Step 6. Receive webhook notifications ------------------------------------------------------------------------------------------------------------------------------------------------- When events occur, Circle sends updates to your endpoint. Here is what a `Transfer` event looks like: { "subscriptionId": "f0332621-a117-4b7b-bdf0-5c61a4681826", "notificationId": "5c5eea9f-398f-426f-a4a5-1bdc28b36d2c", "notificationType": "contracts.eventLog", "notification": { "contractAddress": "0x4abcffb90897fe7ce86ed689d1178076544a021b", "blockchain": "ARC-TESTNET", "txHash": "0xe15d6dbb50178f60930b8a3e3e775f3c022505ea2e351b6c2c2985d2405c8ebc", "userOpHash": "0x78c3e8185ff9abfc7197a8432d9b79566123616c136001e609102c97e732e55e", "blockHash": "0x0ad6bf57a110d42620defbcb9af98d6223f060de588ed96ae495ddeaf3565c8d", "blockHeight": 22807198, "eventSignature": "Transfer(address,address,uint256)", "eventSignatureHash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topics": [\ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\ "0x0000000000000000000000000000000000000000000000000000000000000000",\ "0x000000000000000000000000bcf83d3b112cbf43b19904e376dd8dee01fe2758"\ ], "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", "firstConfirmDate": "2026-01-21T06:53:12Z" }, "timestamp": "2026-01-21T06:53:13.194467201Z", "version": 2 } **Key fields:** * `notificationType`: Always `"contracts.eventLog"` for event monitor webhooks * `notification.eventSignature`: The event that was emitted * `notification.contractAddress`: Address of the contract that emitted the event * `notification.blockchain`: The blockchain network (for example, `ARC-TESTNET`) * `notification.txHash`: Transaction hash where the event occurred * `notification.userOpHash`: User operation hash (for smart contract accounts) * `notification.blockHash`: Hash of the block containing the transaction * `notification.blockHeight`: Block number where the event occurred * `notification.eventSignatureHash`: Keccak256 hash of the event signature * `notification.topics`: Indexed event parameters (for example, `from` and `to` addresses) * `notification.data`: Non-indexed event parameters (for example, token amount) * `notification.firstConfirmDate`: Timestamp when the event was first confirmed * `timestamp`: Timestamp when the webhook was sent * `version`: Webhook payload version You can verify webhook delivery status in the [Developer Console](https://console.circle.com/) under Contracts → Monitoring. [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#step-7-retrieve-event-logs) Step 7. Retrieve event logs ----------------------------------------------------------------------------------------------------------------------------- You can also query event logs with the API. This is useful for past events or if you prefer polling. **Webhooks vs Polling**: Webhooks send real-time updates (push). Polling needs periodic API calls (pull). Use webhooks for production and polling for testing or past queries. get-event-logs.ts get\_event\_logs.py import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const contractClient = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); async function getEventLogs() { try { const response = await contractClient.listEventLogs({ contractAddress: process.env.CONTRACT_ADDRESS, blockchain: "ARC-TESTNET", pageSize: 10, }); console.log(JSON.stringify(response.data, null, 2)); } catch (error) { console.error("Error fetching event logs:", error.message); throw error; } } getEventLogs(); **Run the script:** Node.js Python npm run get-event-logs Replace `CONTRACT_ADDRESS` with your contract address. You can get this address when you deploy the contract, or by listing your contracts with `listContracts()`. **Response:** { "eventLogs": [\ {\ "id": "019bf987-f901-7145-9e95-55f177b05b24",\ "subscriptionId": "019bf984-b4da-7026-a3d2-674ce371a933",\ "contractId": "019bf8be-7be5-7a3e-89cc-05bcd7413f20",\ "contractName": "TestERC20Token",\ "blockchain": "ARC-TESTNET",\ "txHash": "0x3bfbab5d5ce0d1a5d682cbc742d3940cf59db0369d173b71ba2a3b8f43bfbcb1",\ "logIndex": "50",\ "blockHash": "0x7d12148f9331556b31f84f58a41b7ff16eaaa47940f9e86733037d7ab74d858e",\ "blockHeight": 23686153,\ "contractAddress": "0x281156899e5bd6fecf1c0831ee24894eeeaea2f8",\ "eventSignature": "Transfer(address,address,uint256)",\ "eventSignatureHash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\ "topics": [\ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\ "0x0000000000000000000000000000000000000000000000000000000000000000",\ "0x000000000000000000000000bcf83d3b112cbf43b19904e376dd8dee01fe2758"\ ],\ "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",\ "decodedTopics": null,\ "decodedData": null,\ "userOpHash": "0x66befac1a371fcdddf1566215e4677127e111dff9253f306f7096fed8642a208",\ "firstConfirmDate": "2026-01-26T08:59:55Z",\ "createDate": "2026-01-26T08:59:56.545962Z",\ "updateDate": "2026-01-26T08:59:56.545962Z"\ }\ ] } You can view, update, and delete event monitors with the Circle Contracts API. See the [API Reference](https://developers.circle.com/api-reference/contracts/smart-contract-platform/get-event-monitors) for details on managing your monitors. [​](https://docs.arc.network/arc/tutorials/monitor-contract-events#summary) Summary -------------------------------------------------------------------------------------- After completing this tutorial, you’ve successfully: * Set up webhook endpoints using webhook.site or `ngrok` * Registered webhooks in the Developer Console * Created event monitors for specific contract events * Received real-time webhook updates for contract events * Retrieved past event logs with the Circle SDK Was this page helpful? YesNo [Interact with contracts](https://docs.arc.network/arc/tutorials/interact-with-contracts) [Register your first AI agent](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Transfer USDC or EURC - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Transfer USDC or EURC [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Summary](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#summary) This tutorial walks you through transferring USDC or EURC from one wallet address to another on Arc Testnet. Select the tab that matches your preferred setup. * Circle Wallets * Viem [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------ Before you begin, make sure you have: 1. A [Circle Developer Console](https://console.circle.com/) account 2. An API key created in the Console: **Keys → Create a key → API key → Standard Key** 3. Your [Entity Secret registered](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#step-1-set-up-your-project) Step 1. Set up your project --------------------------------------------------------------------------------------------------------------------------- In this step, you set up your local development environment and install the required dependencies. ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#1-1-create-the-project-and-install-dependencies) 1.1. Create the project and install dependencies Create a new directory, navigate to it and initialize a new project. Node.js Python mkdir transfer-funds && cd transfer-funds npm init -y npm pkg set type=module In the project directory, install the [Circle Dev-Controlled Wallets SDK](https://developers.circle.com/sdks) . It is also possible to [call the API directly](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/) if you can’t use the SDK in your project. Node.js Python npm install @circle-fin/developer-controlled-wallets ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#1-3-set-environment-variables) 1.3. Set environment variables Create a `.env` file in the project directory with your Circle credentials, replacing these placeholders with your own credentials: .env CIRCLE_API_KEY=YOUR_API_KEY CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET * `CIRCLE_API_KEY` is your Circle Developer API key for Wallets API requests. * `CIRCLE_ENTITY_SECRET` is your registered entity secret used to authorize developer-controlled wallet operations. In the Node.js examples, npm commands can load variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#step-2-set-up-your-wallets) Step 2. Set up your wallets --------------------------------------------------------------------------------------------------------------------------- In this step, you create two Arc Testnet dev-controlled wallets and fund one of them with testnet USDC or EURC for the transfer flow. If you already have two Arc Testnet dev-controlled wallets and one is funded with USDC or EURC, skip to [Step 3](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#step-3-transfer-usdc-/-eurc) . ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#2-1-create-wallets) 2.1. Create wallets Import the Wallets SDK and initialize the client using your API key and Entity Secret. Dev-controlled wallets are created in a [wallet set](https://developers.circle.com/wallets/dev-controlled/create-your-first-wallet#1-create-a-wallet-set) , which serves as the source from which individual wallet keys are derived. Node.js Python import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const client = initiateDeveloperControlledWalletsClient({ apiKey: "", entitySecret: "", }); // Create a wallet set const walletSetResponse = await client.createWalletSet({ name: "Wallet Set 1", }); // Create a wallet on Arc Testnet const walletsResponse = await client.createWallets({ blockchains: ["ARC-TESTNET"], count: 2, walletSetId: walletSetResponse.data?.walletSet?.id ?? "", }); If you’re calling the API directly, you’ll need to make two requests: one to [create the wallet set](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-wallet-set) ; one to [create the wallet](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-wallet) .Be sure to replace the [Entity Secret ciphertext](https://developers.circle.com/wallets/dev-controlled/entity-secret-management#what-is-an-entity-secret-ciphertext)  and the idempotency key in your request. If you’re using the SDKs, this is handled automatically for you. You should have two new Externally Owned Account (EOA) developer-controlled wallets that you can also see from the [Circle Developer Console](https://console.circle.com/wallets/dev/wallets) . The API response will look similar to the following: [\ {\ "id": "a2f67c91-b7e3-5df4-9c8e-42bbd51a9fcb",\ "state": "LIVE",\ "walletSetId": "5c3e9f20-8d4b-55a1-a63b-c21f44de8a72",\ "custodyType": "DEVELOPER",\ "refId": "",\ "name": "",\ "address": "0x9eab451f27dca39bd3f5d76ef28c86cc0b3a72df",\ "blockchain": "ARC-TESTNET",\ "accountType": "EOA",\ "updateDate": "2025-11-07T01:35:03Z",\ "createDate": "2025-11-07T01:35:03Z"\ },\ {\ "id": "c84d12a4-f6a9-5df8-8b44-92ff7cc94e32",\ "state": "LIVE",\ "walletSetId": "5c3e9f20-8d4b-55a1-a63b-c21f44de8a72",\ "custodyType": "DEVELOPER",\ "refId": "",\ "name": "",\ "address": "0xb37ac90d1a657c04a8518b6f7bda2b37e4f8d221",\ "blockchain": "ARC-TESTNET",\ "accountType": "EOA",\ "updateDate": "2025-11-07T01:35:06Z",\ "createDate": "2025-11-07T01:35:06Z"\ }\ ] ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#2-2-fund-a-wallet-with-testnet-stablecoins) 2.2. Fund a wallet with testnet stablecoins Obtain testnet USDC or EURC from the [Circle Faucet](https://faucet.circle.com/) or the [Console Faucet](https://console.circle.com/faucet) to perform actions like making transfers and paying gas fees. You’ll need a funded balance to execute transactions using your dev-controlled wallet. ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#2-3-check-the-wallet-balances) 2.3. Check the wallet balances You can check your wallet balances from the [Circle Developer Console](https://console.circle.com/wallets/dev/wallets) or programmatically by making a request to [GET /wallets/{id}/balances](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/list-wallet-balance) with the specified wallet ID. Node.js Python cURL const response = await client.getWalletTokenBalance({ id: "", }); [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#step-3-transfer-usdc-/-eurc) Step 3. Transfer USDC / EURC ----------------------------------------------------------------------------------------------------------------------------- In this step, you set up your script, execute the USDC or EURC transfer, and check the result. ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#3-1-set-up-the-transfer-script-and-execute-the-transfer) 3.1. Set up the transfer script and execute the transfer Replace the `walletAddress` field with the address of the funded wallet, and the `destinationAddress` field with the address of the other wallet. * USDC * EURC Node.js Python cURL import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const client = initiateDeveloperControlledWalletsClient({ apiKey: "", entitySecret: "", }); const transferResponse = await client.createTransaction({ amount: ["0.1"], // Transfer 0.1 USDC destinationAddress: "", tokenAddress: "0x3600000000000000000000000000000000000000", // USDC contract address on Arc Testnet blockchain: "ARC-TESTNET", walletAddress: "", fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(transferResponse.data); Node.js Python cURL import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const client = initiateDeveloperControlledWalletsClient({ apiKey: "", entitySecret: "", }); const transferResponse = await client.createTransaction({ amount: ["0.1"], // Transfer 0.1 EURC destinationAddress: "", tokenAddress: "0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a", // EURC contract address on Arc Testnet blockchain: "ARC-TESTNET", walletAddress: "", fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(transferResponse.data); If the script runs successfully, you should receive a response object with a transaction ID and the state of the transaction that looks similar to the following: { "id": "70cb796b-5c43-5076-a790-3525f6d8424c", "state": "INITIATED" } ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#3-2-verify-the-status-of-the-transfer) 3.2. Verify the status of the transfer You can check the status of the transfer with the `getTransaction` method by providing the transaction ID obtained from the previous step. Node.js Python cURL const response = await client.getTransaction({ id: "", }); console.log(response.data); You can verify that the transaction was successful by checking the details in the returned object, which should look similar to the following: { "data": { "transaction": { "id": "70cb796b-5c43-5076-a790-3525f6d8424c", "blockchain": "ARC-TESTNET", "tokenId": "15dc2b5d-0994-58b0-bf8c-3a0501148ee8", "walletId": "f8a9993d-5a59-58df-b3e0-206c6e81ea57", "sourceAddress": "0x3bafa3a0987699391a2003c3aa06d41b0209c397", "destinationAddress": "0x1f5ee284571f4bb888ceda4cc7b6e5e15829a1ea", "transactionType": "OUTBOUND", "custodyType": "DEVELOPER", "state": "COMPLETE", "transactionScreeningEvaluation": { "screeningDate": "2026-01-07T04:49:09Z" }, "amounts": [\ "0.1"\ ], "nfts": null, "txHash": "0x2e312718a2b6663cf20862e71b52dcb5404c9dd16510a08c5c9f47a78aabf644", "blockHash": "0x7474b111d671de75e7b606b8e1a1508c9bcef0eafc718843accb900510f35bf9", "blockHeight": 20375164, "networkFee": "0.003556682015901", "firstConfirmDate": "2026-01-07T04:49:11Z", "operation": "TRANSFER", "feeLevel": "MEDIUM", "estimatedFee": { "gasLimit": "21000", "networkFee": "0.006916682015901", "baseFee": "160", "priorityFee": "9.365810281", "maxFee": "329.365810281" }, "refId": "", "abiParameters": null, "createDate": "2026-01-07T04:49:09Z", "updateDate": "2026-01-07T04:49:11Z" } } } You can also copy the transaction hash (`txHash`) value and look up the transaction details on the [Arc Testnet explorer](https://testnet.arcscan.app/) . [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#prerequisites-2) Prerequisites -------------------------------------------------------------------------------------------------- Before you begin, ensure that you’ve: * Installed [Node.js v22+](https://nodejs.org/) . * Created an [Arc Testnet](https://docs.arc.network/arc/references/connect-to-arc#wallet-setup) wallet and funded it with testnet USDC or EURC and testnet native tokens. * Chosen a recipient wallet address on Arc Testnet. [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#step-1-set-up-your-project-2) Step 1. Set up your project ----------------------------------------------------------------------------------------------------------------------------- This step shows you how to prepare your project and environment. ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#1-1-create-the-project-and-install-dependencies-2) 1.1. Create the project and install dependencies Create a new directory and install App Kit and its dependencies: Shell # Set up your directory and initialize a Node.js project mkdir transfer-funds && cd transfer-funds npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" # Install runtime dependencies npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem # Install dev dependencies npm install --save-dev typescript tsx ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#1-2-configure-typescript-optional-2) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: Shell npx tsc --init Then, update the `tsconfig.json` file: Shell cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#1-3-set-environment-variables-2) 1.3. Set environment variables Create an `.env` file in the project directory: Shell touch .env Then, add your wallet private key and recipient address. Replace `0xYOUR_PRIVATE_KEY` with the `0x`\-prefixed private key for your Arc Testnet wallet and `YOUR_RECIPIENT_ADDRESS` with the destination wallet address: .env PRIVATE_KEY=0xYOUR_PRIVATE_KEY RECIPIENT_ADDRESS=YOUR_RECIPIENT_ADDRESS * `PRIVATE_KEY` is the `0x`\-prefixed private key for the funded Arc Testnet wallet that sends the tokens. * `RECIPIENT_ADDRESS` is the Arc Testnet wallet address that receives the tokens. The `npm run start` command loads these variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#step-2-send-usdc-or-eurc) Step 2. Send USDC or EURC ----------------------------------------------------------------------------------------------------------------------- This step shows you how to set up your script, send tokens from your wallet to a recipient on Arc Testnet, and check the result. ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#2-1-create-the-script) 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 wallet to a recipient on Arc Testnet. To send EURC instead, change `token: "USDC"` to `token: "EURC"`. TypeScript import { AppKit, type SendParams } from "@circle-fin/app-kit"; import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2"; import { inspect } from "node:util"; const kit = new AppKit(); function createSendParams( adapter: ReturnType, ): SendParams { return { from: { adapter, chain: "Arc_Testnet" }, to: process.env.RECIPIENT_ADDRESS as string, amount: "1.00", token: "USDC", }; } async function sendTokens(): Promise { const adapter = createViemAdapterFromPrivateKey({ privateKey: process.env.PRIVATE_KEY as string, }); const sendParams = createSendParams(adapter); const result = await kit.send(sendParams); console.log(inspect(result, false, null, true)); } void sendTokens(); ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#2-2-run-the-script) 2.2. Run the script Save the `index.ts` file and run the script in your terminal: Shell npm run start ### [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#2-3-verify-the-transaction) 2.3. Verify the transaction After the script finishes, find the returned result in the terminal output. Use the transaction explorer URL to verify the amount and recipient on Arc Testnet.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: Shell { name: "transfer", state: "success", txHash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", explorerUrl: "https://testnet.arcscan.app/tx/0x1234567890abcdef..." } * * * [​](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc#summary) Summary ------------------------------------------------------------------------------------ After completing this tutorial, you’ve successfully: * Set up a wallet workflow for either Circle Wallets or a self-managed wallet * Prepared your wallet with testnet tokens * Transferred USDC or EURC from one wallet to another Was this page helpful? YesNo [Bridge USDC to Arc](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc) [Access USDC crosschain](https://docs.arc.network/arc/tutorials/access-usdc-crosschain) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Interact with contracts - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/interact-with-contracts#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Interact with contracts [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/arc/tutorials/interact-with-contracts#prerequisites) * [Step 1. Update your project](https://docs.arc.network/arc/tutorials/interact-with-contracts#step-1-update-your-project) * [1.1. Set environment variables](https://docs.arc.network/arc/tutorials/interact-with-contracts#1-1-set-environment-variables) * [1.2. Add npm scripts](https://docs.arc.network/arc/tutorials/interact-with-contracts#1-2-add-npm-scripts) * [Step 2. Interact with contracts](https://docs.arc.network/arc/tutorials/interact-with-contracts#step-2-interact-with-contracts) * [Summary](https://docs.arc.network/arc/tutorials/interact-with-contracts#summary) This tutorial guides you through interacting with smart contracts deployed on Arc Testnet. You’ll learn how to execute contract functions like minting tokens, transferring assets, and performing contract-specific operations for ERC-20, ERC-721, ERC-1155, and Airdrop contracts. [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#prerequisites) Prerequisites -------------------------------------------------------------------------------------------------- Complete the [Deploy contracts](https://docs.arc.network/arc/tutorials/deploy-contracts) tutorial first. You’ll need a deployed contract. [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#step-1-update-your-project) Step 1. Update your project ----------------------------------------------------------------------------------------------------------------------------- In this step, you update the project you created in the Deploy contracts tutorial with the additional environment variable and npm scripts needed for contract interactions. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#1-1-set-environment-variables) 1.1. Set environment variables Add this new variable to your existing `.env` file (from the Deploy contracts tutorial): .env RECIPIENT_WALLET_ADDRESS=YOUR_RECIPIENT_ADDRESS * `RECIPIENT_WALLET_ADDRESS` is the wallet address that receives transferred tokens during the interaction examples. Your `.env` file should already have `CIRCLE_API_KEY`, `CIRCLE_ENTITY_SECRET`, `WALLET_ID`, `WALLET_ADDRESS`, and `CONTRACT_ADDRESS` from the Deploy contracts tutorial. You’re only adding 1 new variable here. The npm run commands in this tutorial load variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#1-2-add-npm-scripts) 1.2. Add npm scripts Add run scripts for contract interactions to your `package.json`: npm pkg set scripts.interact-erc20="tsx --env-file=.env interact-erc20.ts" npm pkg set scripts.interact-erc721="tsx --env-file=.env interact-erc721.ts" npm pkg set scripts.interact-erc1155="tsx --env-file=.env interact-erc1155.ts" npm pkg set scripts.interact-airdrop="tsx --env-file=.env interact-airdrop.ts" [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#step-2-interact-with-contracts) Step 2. Interact with contracts ------------------------------------------------------------------------------------------------------------------------------------- Select the contract type you want to interact with from the tabs below. * ERC-20 * ERC-721 * ERC-1155 * Airdrop [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#interact-with-erc-20-contracts) Interact with ERC-20 contracts ------------------------------------------------------------------------------------------------------------------------------------ ERC-20 tokens support standard fungible token operations. You’ll learn to mint new tokens and transfer them between addresses. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#mint-tokens) Mint tokens Use the `mintTo` function to mint tokens. The wallet must have `MINTER_ROLE`. Node.js Python cURL import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const mintResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "mintTo(address,uint256)", abiParameters: [\ process.env.WALLET_ADDRESS,\ "1000000000000000000", // 1 token with 18 decimals\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(mintResponse.data, null, 2)); **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } **Token decimals**: ERC-20 tokens typically use 18 decimals. To mint 1 token, use `1000000000000000000` (1 × 10^18). ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#transfer-tokens) Transfer tokens Use the `transfer` function to send tokens to another address. Node.js Python cURL const transferResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "transfer(address,uint256)", abiParameters: [\ process.env.RECIPIENT_WALLET_ADDRESS,\ "1000000000000000000", // 1 token with 18 decimals\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(transferResponse.data, null, 2)); **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#full-erc-20-interaction-script) Full ERC-20 interaction script Here’s the full script combining mint and transfer operations: interact-erc20.ts interact\_erc20.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); async function main() { // Mint tokens const mintResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "mintTo(address,uint256)", abiParameters: [\ process.env.WALLET_ADDRESS,\ "1000000000000000000", // 1 token with 18 decimals\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(mintResponse.data, null, 2)); // Transfer tokens const transferResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "transfer(address,uint256)", abiParameters: [\ process.env.RECIPIENT_WALLET_ADDRESS,\ "1000000000000000000", // 1 token with 18 decimals\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(transferResponse.data, null, 2)); } main(); **Run the script:** Node.js Python npm run interact-erc20 [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#interact-with-erc-721-contracts) Interact with ERC-721 contracts -------------------------------------------------------------------------------------------------------------------------------------- ERC-721 tokens are unique tokens. Each token has a unique ID and can have associated metadata stored on IPFS or other storage. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#mint-tokens-2) Mint tokens Use the `mintTo` function to mint tokens. The wallet must have `MINTER_ROLE`. Node.js Python cURL import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const mintResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "mintTo(address,string)", abiParameters: [\ process.env.WALLET_ADDRESS,\ "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei",\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(mintResponse.data, null, 2)); **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } **Metadata URI**: The second parameter is the token metadata URI. It typically points to an IPFS hash containing the token’s metadata (name, description, image, etc.). You can use the example IPFS URI from the code sample for testing. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#transfer-tokens-2) Transfer tokens Use the `transferFrom` or `safeTransferFrom` function to transfer tokens between addresses. Node.js Python cURL const transferResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "safeTransferFrom(address,address,uint256)", abiParameters: [\ "",\ "",\ "1", // Token ID\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(transferResponse.data, null, 2)); ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#full-erc-721-interaction-script) Full ERC-721 interaction script Here’s the full script combining mint and transfer operations: interact-erc721.ts interact\_erc721.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); async function main() { // Mint token const mintResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "mintTo(address,string)", abiParameters: [\ process.env.WALLET_ADDRESS,\ "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei",\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(mintResponse.data, null, 2)); // Transfer token (token ID 1) const transferResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "safeTransferFrom(address,address,uint256)", abiParameters: [\ process.env.WALLET_ADDRESS,\ process.env.RECIPIENT_WALLET_ADDRESS,\ "1", // Token ID\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(transferResponse.data, null, 2)); } main(); **Run the script:** Node.js Python npm run interact-erc721 **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#interact-with-erc-1155-contracts) Interact with ERC-1155 contracts ---------------------------------------------------------------------------------------------------------------------------------------- ERC-1155 contracts support multiple token types in a single contract. Each token has a unique ID and can be fungible or non-fungible. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#mint-tokens-3) Mint tokens Use the `mintTo` function to mint tokens. The wallet must have `MINTER_ROLE`. The first mint requires the maximum uint256 value to create token ID 0. For subsequent mints, always use `0` which creates the next token ID. Node.js Python cURL import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const mintResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "mintTo(address,uint256,string,uint256)", abiParameters: [\ process.env.WALLET_ADDRESS,\ "115792089237316195423570985008687907853269984665640564039457584007913129639935", // Max uint256 = ID 0\ "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei",\ "1", // Amount\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(mintResponse.data, null, 2)); **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } **ERC-1155 Token ID Creation**: The first mint of each token ID requires passing the maximum uint256 value (`2^256 - 1` or `115792089237316195423570985008687907853269984665640564039457584007913129639935`) to create token ID 0 in the contract. For all subsequent mints, use `0` which creates the next sequential token ID (1, 2, 3, etc.). This is an ERC-1155 standard requirement for lazy minting, where token IDs are created on demand rather than pre-initialized. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#batch-transfer-tokens) Batch transfer tokens Use the `safeBatchTransferFrom` function to transfer multiple token types in a single transaction. Node.js Python cURL const transferResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)", abiParameters: [\ "",\ "",\ ["0"], // Token IDs\ ["1"], // Amounts\ "0x", // Empty bytes\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(transferResponse.data, null, 2)); ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#full-erc-1155-interaction-script) Full ERC-1155 interaction script Here’s the full script combining mint and batch transfer operations: interact-erc1155.ts interact\_erc1155.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); async function main() { // Mint tokens (token ID 0) const mintResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "mintTo(address,uint256,string,uint256)", abiParameters: [\ process.env.WALLET_ADDRESS,\ "115792089237316195423570985008687907853269984665640564039457584007913129639935", // Max uint256 = ID 0\ "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei",\ "1", // Amount\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(mintResponse.data, null, 2)); // Batch transfer tokens const transferResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)", abiParameters: [\ process.env.WALLET_ADDRESS,\ process.env.RECIPIENT_WALLET_ADDRESS,\ ["0"], // Token IDs\ ["1"], // Amounts\ "0x", // Empty bytes\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(transferResponse.data, null, 2)); } main(); **Run the script:** Node.js Python npm run interact-erc1155 **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#execute-airdrop-operations) Execute airdrop operations ---------------------------------------------------------------------------------------------------------------------------- The Airdrop contract enables mass token distribution to multiple recipients. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#prerequisites-2) Prerequisites Before executing an airdrop, you need: 1. **A token contract address** - Deploy one using the [ERC-20](https://docs.arc.network/arc/tutorials/deploy-contracts#erc-20) , [ERC-721](https://docs.arc.network/arc/tutorials/deploy-contracts#erc-721) , or [ERC-1155](https://docs.arc.network/arc/tutorials/deploy-contracts#erc-1155) templates, or use an existing token 2. **Token balance** - Your wallet must hold enough tokens to distribute 3. **Token approval** - Call the `approve` or `setApprovalForAll` function on your token contract to allow the airdrop contract to transfer tokens ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#execute-an-erc-20-airdrop) Execute an ERC-20 airdrop Use the `airdropERC20` function to distribute ERC-20 tokens to multiple recipients. Node.js Python cURL import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const airdropResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "airdropERC20(address,(address,uint256)[])", abiParameters: [\ "", // ERC-20 token contract address\ [\ ["", "1000000000000000000"],\ ["", "2000000000000000000"],\ ],\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(airdropResponse.data, null, 2)); **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } **Token contract**: The first parameter is the address of the ERC-20 token contract you want to airdrop. You must deploy this contract first using the [Deploy contracts](https://docs.arc.network/arc/tutorials/deploy-contracts) tutorial. ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#execute-an-erc-721-airdrop) Execute an ERC-721 airdrop Use the `airdropERC721` function to distribute tokens to multiple recipients. Node.js Python cURL const airdropResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "airdropERC721(address,(address,uint256)[])", abiParameters: [\ "", // ERC-721 token contract address\ [\ ["", "1"], // Token ID 1\ ["", "2"], // Token ID 2\ ],\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(airdropResponse.data, null, 2)); **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#execute-an-erc-1155-airdrop) Execute an ERC-1155 airdrop Use the `airdropERC1155` function to distribute ERC-1155 tokens to multiple recipients. Node.js Python cURL const airdropResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "airdropERC1155(address,(address,uint256,uint256)[])", abiParameters: [\ "", // ERC-1155 token contract address\ [\ ["", "0", "10"], // Token ID 0, amount 10\ ["", "1", "5"], // Token ID 1, amount 5\ ],\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(airdropResponse.data, null, 2)); ### [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#full-airdrop-interaction-script) Full airdrop interaction script Here’s the full script for executing an ERC-20 airdrop. You can adapt it for ERC-721 or ERC-1155 by changing the function signature and parameters as shown in the examples previously: interact-airdrop.ts interact\_airdrop.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); async function main() { // Execute ERC-20 airdrop const airdropResponse = await circleDeveloperSdk.createContractExecutionTransaction({ walletId: process.env.WALLET_ID, abiFunctionSignature: "airdropERC20(address,(address,uint256)[])", abiParameters: [\ process.env.TOKEN_CONTRACT_ADDRESS, // ERC-20 token contract address\ [\ [process.env.RECIPIENT_ADDRESS_1, "1000000000000000000"],\ [process.env.RECIPIENT_ADDRESS_2, "2000000000000000000"],\ ],\ ], contractAddress: process.env.CONTRACT_ADDRESS, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(airdropResponse.data, null, 2)); // For ERC-721 airdrop, use: // abiFunctionSignature: "airdropERC721(address,(address,uint256)[])" // abiParameters: [tokenAddress, [[recipient1, tokenId1], [recipient2, tokenId2]]] // For ERC-1155 airdrop, use: // abiFunctionSignature: "airdropERC1155(address,(address,uint256,uint256)[])" // abiParameters: [tokenAddress, [[recipient1, tokenId, amount], [recipient2, tokenId, amount]]] } main(); **Run the script:** Node.js Python npm run interact-airdrop **Response:** { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "state": "INITIATED" } * * * [​](https://docs.arc.network/arc/tutorials/interact-with-contracts#summary) Summary -------------------------------------------------------------------------------------- After completing this tutorial, you’ve learned how to: * Execute contract functions using the Circle SDKs * Mint and transfer tokens for your deployed contracts * Perform contract-specific operations based on token type Was this page helpful? YesNo [Access USDC crosschain](https://docs.arc.network/arc/tutorials/access-usdc-crosschain) [Monitor contract events](https://docs.arc.network/arc/tutorials/monitor-contract-events) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Access USDC crosschain - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Access USDC crosschain [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Summary](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#summary) This tutorial shows an Arc-first Gateway flow: deposit USDC from an Arc wallet into a unified Gateway balance on Arc Testnet, then transfer that balance to Ethereum Sepolia. Gateway supports unified USDC balances across multiple EVM chains. This quickstart shows the Arc Testnet to Ethereum Sepolia flow for clarity. The config objects also include other supported EVM chains that you can swap in as needed. Select the tab that matches your preferred setup. For Solana-specific Gateway flows, use the dedicated [Circle Gateway quickstarts](https://developers.circle.com/gateway/quickstarts/unified-balance-solana) . * Circle Wallets * Viem [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. A [Circle Developer Console](https://console.circle.com/) account 2. An API key created in the Console 3. Your [Entity Secret registered](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) 4. Testnet USDC and native tokens on Arc Testnet 5. Testnet native tokens on Ethereum Sepolia for the destination mint [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-1-set-up-your-project) Step 1. Set up your project ---------------------------------------------------------------------------------------------------------------------------- In this step, you create the project, install dependencies, and configure the environment for the Arc-first Gateway flow. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#1-1-create-the-project-and-install-dependencies) 1.1. Create the project and install dependencies mkdir arc-gateway-balance cd arc-gateway-balance npm init -y npm pkg set type=module npm pkg set scripts.deposit="tsx --env-file=.env deposit.ts" npm pkg set scripts.transfer="tsx --env-file=.env transfer.ts" npm pkg set scripts.balances="tsx --env-file=.env balances.ts" npm install @circle-fin/developer-controlled-wallets npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#1-3-set-environment-variables) 1.3. Set environment variables Create a `.env` file in the project directory: .env CIRCLE_API_KEY=YOUR_API_KEY CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET DEPOSITOR_ADDRESS=YOUR_ARC_WALLET_ADDRESS RECIPIENT_ADDRESS=YOUR_ETHEREUM_ADDRESS * `CIRCLE_API_KEY` is your Circle Developer API key. * `CIRCLE_ENTITY_SECRET` is your registered Entity Secret. * `DEPOSITOR_ADDRESS` is the Arc wallet address that deposits into Gateway and signs the burn intent. * `RECIPIENT_ADDRESS` is the Ethereum Sepolia address that receives the minted USDC. The `npm run` commands in this tutorial load variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-2-set-up-and-fund-your-wallets) Step 2. Set up and fund your wallets ---------------------------------------------------------------------------------------------------------------------------------------------- In this step, you create matching dev-controlled EVM wallets on Arc Testnet and Ethereum Sepolia and fund them for the Gateway flow. If you already have funded wallets on both chains, skip ahead to the [deposit step](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-3-deposit-usdc-into-a-gateway-balance-on-arc) . ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#2-1-create-wallets) 2.1. Create wallets Create one dev-controlled wallet on Arc Testnet and one on Ethereum Sepolia using the same `refId`. Circle assigns the same EVM address to both wallets, which keeps the source and destination flow easier to follow.If you want to mint on another supported EVM destination later, create a matching dev-controlled wallet on that chain with the same `refId`, then update `DESTINATION_CHAIN` and `RECIPIENT_ADDRESS` to match. create-wallets.ts import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const client = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY!, entitySecret: process.env.CIRCLE_ENTITY_SECRET!, }); async function createWallets() { // Create one wallet set, then derive matching EVM wallets on both chains. const walletSet = await client.createWalletSet({ name: "Arc Gateway Wallets", }); /* * Supported EVM testnet wallet blockchains: * ETH-SEPOLIA | AVAX-FUJI | MATIC-AMOY | ARB-SEPOLIA * UNI-SEPOLIA | BASE-SEPOLIA | OP-SEPOLIA | ARC-TESTNET */ const response = await client.createWallets({ blockchains: ["ARC-TESTNET", "ETH-SEPOLIA"], count: 1, walletSetId: walletSet.data?.walletSet?.id ?? "", accountType: "EOA", metadata: [{ refId: "arc-gateway-depositor" }], }); console.log(JSON.stringify(response.data?.wallets, null, 2)); } void createWallets(); If you’re calling the API directly, you’ll need to make two requests: one to create the wallet set and one to create the wallet. Be sure to replace the Entity Secret ciphertext and the idempotency key in your request. If you’re using the SDKs, this is handled automatically for you. Run the script: npx tsx --env-file=.env create-wallets.ts After the wallets are created, update both `DEPOSITOR_ADDRESS` and `RECIPIENT_ADDRESS` in `.env`. You can use the same EVM address for both in this quickstart.This quickstart uses the same EVM address for `DEPOSITOR_ADDRESS` and `RECIPIENT_ADDRESS`. That way, the same dev-controlled wallet can receive the USDC and submit the mint transaction on Ethereum Sepolia. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#2-2-fund-your-wallets) 2.2. Fund your wallets To follow this flow: * fund the Arc Testnet wallet with testnet USDC and native tokens * fund the Ethereum Sepolia wallet with native tokens for the destination mint Use the [Circle Faucet](https://faucet.circle.com/) for Arc Testnet USDC and the [Ethereum Sepolia faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia) for destination gas. [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-3-deposit-usdc-into-a-gateway-balance-on-arc) Step 3. Deposit USDC into a Gateway balance on Arc -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In this step, you deposit USDC from Arc Testnet into your unified Gateway balance. The script fixes the source chain to Arc Testnet, but the `SUPPORTED_EVM_CHAINS` object shows the broader EVM support you can extend later. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#3-1-create-the-shared-config-file) 3.1. Create the shared config file config.ts export const GATEWAY_WALLET_ADDRESS = "0x0077777d7EBA4688BDeF3E311b846F25870A19B9"; export const GATEWAY_MINTER_ADDRESS = "0x0022222ABE238Cc2C7Bb1f21003F0a260052475B"; export const SOURCE_CHAIN = "arcTestnet" as const; export const DESTINATION_CHAIN = "sepolia" as const; export const SUPPORTED_EVM_CHAINS = { sepolia: { label: "Ethereum Sepolia", walletChain: "ETH-SEPOLIA", domainId: 0, usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", }, baseSepolia: { label: "Base Sepolia", walletChain: "BASE-SEPOLIA", domainId: 6, usdcAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", }, avalancheFuji: { label: "Avalanche Fuji", walletChain: "AVAX-FUJI", domainId: 1, usdcAddress: "0x5425890298aed601595a70AB815c96711a31Bc65", }, arcTestnet: { label: "Arc Testnet", walletChain: "ARC-TESTNET", domainId: 26, usdcAddress: "0x3600000000000000000000000000000000000000", }, arbitrumSepolia: { label: "Arbitrum Sepolia", walletChain: "ARB-SEPOLIA", domainId: 3, usdcAddress: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", }, optimismSepolia: { label: "OP Sepolia", walletChain: "OP-SEPOLIA", domainId: 2, usdcAddress: "0x5fd84259d66Cd46123540766Be93DFE6D43130D7", }, polygonAmoy: { label: "Polygon Amoy", walletChain: "MATIC-AMOY", domainId: 7, usdcAddress: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582", }, unichainSepolia: { label: "Unichain Sepolia", walletChain: "UNI-SEPOLIA", domainId: 10, usdcAddress: "0x31d0220469e10c4E71834a79b1f276d740d3768F", }, } as const; export function parseUsdc(value: string): string { const [whole, decimal = ""] = value.split("."); const decimal6 = (decimal + "000000").slice(0, 6); return BigInt((whole || "0") + decimal6).toString(); } See all 63 lines ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#3-2-create-the-deposit-script) 3.2. Create the deposit script The main logic performs two key actions: * **Approve USDC transfers**: It calls the `approve` method on the USDC contract to allow the Gateway Wallet contract to transfer USDC from your wallet. * **Deposit USDC into Gateway**: After receiving the approval transaction hash, it calls the `deposit` method on the Gateway Wallet contract. deposit.ts import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; import { GATEWAY_WALLET_ADDRESS, SOURCE_CHAIN, SUPPORTED_EVM_CHAINS, parseUsdc, } from "./config.js"; const DEPOSIT_AMOUNT_USDC = "2"; async function waitForTxCompletion( client: ReturnType, txId: string, label: string, ) { const terminalStates = new Set([\ "COMPLETE",\ "CONFIRMED",\ "FAILED",\ "DENIED",\ "CANCELLED",\ ]); while (true) { const { data } = await client.getTransaction({ id: txId }); const state = data?.transaction?.state; if (state && terminalStates.has(state)) { console.log(`${label} final state: ${state}`); if (state !== "COMPLETE" && state !== "CONFIRMED") { throw new Error(`${label} failed with state ${state}`); } return; } await new Promise((resolve) => setTimeout(resolve, 3000)); } } async function main() { const chain = SUPPORTED_EVM_CHAINS[SOURCE_CHAIN]; const client = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY!, entitySecret: process.env.CIRCLE_ENTITY_SECRET!, }); const amount = parseUsdc(DEPOSIT_AMOUNT_USDC); console.log(`Approving ${DEPOSIT_AMOUNT_USDC} USDC on ${chain.label}...`); // Approve Gateway Wallet to spend USDC const approveTx = await client.createContractExecutionTransaction({ walletAddress: process.env.DEPOSITOR_ADDRESS!, blockchain: chain.walletChain, contractAddress: chain.usdcAddress, abiFunctionSignature: "approve(address,uint256)", abiParameters: [GATEWAY_WALLET_ADDRESS, amount], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); const approveTxId = approveTx.data?.id; if (!approveTxId) throw new Error("Failed to create approve transaction"); await waitForTxCompletion(client, approveTxId, "USDC approve"); console.log(`USDC approve complete on ${chain.label}: ${approveTxId}`); console.log( `Depositing ${DEPOSIT_AMOUNT_USDC} USDC into Gateway on ${chain.label}...`, ); // Deposit USDC into Gateway const depositTx = await client.createContractExecutionTransaction({ walletAddress: process.env.DEPOSITOR_ADDRESS!, blockchain: chain.walletChain, contractAddress: GATEWAY_WALLET_ADDRESS, abiFunctionSignature: "deposit(address,uint256)", abiParameters: [chain.usdcAddress, amount], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); const depositTxId = depositTx.data?.id; if (!depositTxId) throw new Error("Failed to create deposit transaction"); await waitForTxCompletion(client, depositTxId, "Gateway deposit"); console.log(`Gateway deposit complete on ${chain.label}: ${depositTxId}`); } void main(); Run the deposit script to deposit USDC from Arc Testnet into your Gateway balance. npm run deposit Wait for the [required number of block confirmations](https://developers.circle.com/gateway/references/supported-blockchains#required-block-confirmations) . Once the Arc deposit transaction is final, the funds become available in your Gateway balance. Note that for certain chains, finality may take up to 20 minutes to be reached. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#3-3-check-the-gateway-balances) 3.3. Check the Gateway balances Create a balance script that queries your unified Gateway balance across the configured EVM domains. balances.ts import { SUPPORTED_EVM_CHAINS } from "./config.js"; interface GatewayBalancesResponse { balances: Array<{ domain: number; balance: string; }>; } async function main() { const depositor = process.env.DEPOSITOR_ADDRESS!; console.log(`Gateway balances for ${depositor}:`); // Query every configured Gateway domain to inspect the unified balance. const response = await fetch( "https://gateway-api-testnet.circle.com/v1/balances", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: "USDC", sources: Object.values(SUPPORTED_EVM_CHAINS).map((chain) => ({ domain: chain.domainId, depositor, })), }), }, ); const result = (await response.json()) as GatewayBalancesResponse; for (const balance of result.balances) { const chain = Object.values(SUPPORTED_EVM_CHAINS).find( (item) => item.domainId === balance.domain, )?.label ?? `Domain ${balance.domain}`; console.log(`${chain}: ${balance.balance} USDC`); } } void main(); Run the balance script to check the balances on the Gateway Wallet. npm run balances [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-4-transfer-usdc-from-the-arc-gateway-balance-to-ethereum) Step 4. Transfer USDC from the Arc Gateway balance to Ethereum -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In this step, you burn from the Arc Gateway balance and mint on Ethereum Sepolia. The same script shape works for other supported EVM destinations after you create and fund a matching dev-controlled wallet on that chain and update `DESTINATION_CHAIN` and `RECIPIENT_ADDRESS`.In this flow, `RECIPIENT_ADDRESS` receives the USDC, and `DEPOSITOR_ADDRESS` submits the mint transaction on Ethereum Sepolia. This quickstart keeps them the same. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#4-1-create-the-transfer-script) 4.1. Create the transfer script This example submits one burn intent for clarity. You can also submit multiple burn intents to the Gateway API in a single request and receive a single attestation response to use when minting on the destination chain. transfer.ts import { randomBytes } from "node:crypto"; import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; import { DESTINATION_CHAIN, GATEWAY_MINTER_ADDRESS, GATEWAY_WALLET_ADDRESS, SOURCE_CHAIN, SUPPORTED_EVM_CHAINS, parseUsdc, } from "./config.js"; const TRANSFER_AMOUNT_USDC = "1"; const MAX_FEE = 2_010000n; const MAX_BLOCK_HEIGHT = ((1n << 256n) - 1n).toString(); const domain = { name: "GatewayWallet", version: "1" }; const EIP712Domain = [\ { name: "name", type: "string" },\ { name: "version", type: "string" },\ ] as const; const TransferSpec = [\ { name: "version", type: "uint32" },\ { name: "sourceDomain", type: "uint32" },\ { name: "destinationDomain", type: "uint32" },\ { name: "sourceContract", type: "bytes32" },\ { name: "destinationContract", type: "bytes32" },\ { name: "sourceToken", type: "bytes32" },\ { name: "destinationToken", type: "bytes32" },\ { name: "sourceDepositor", type: "bytes32" },\ { name: "destinationRecipient", type: "bytes32" },\ { name: "sourceSigner", type: "bytes32" },\ { name: "destinationCaller", type: "bytes32" },\ { name: "value", type: "uint256" },\ { name: "salt", type: "bytes32" },\ { name: "hookData", type: "bytes" },\ ] as const; const BurnIntent = [\ { name: "maxBlockHeight", type: "uint256" },\ { name: "maxFee", type: "uint256" },\ { name: "spec", type: "TransferSpec" },\ ] as const; function addressToBytes32(address: string): `0x${string}` { return `0x${address.toLowerCase().replace(/^0x/, "").padStart(64, "0")}`; } function stringifyWithBigints(value: T): string { return JSON.stringify(value, (_key, current) => typeof current === "bigint" ? current.toString() : current, ); } async function waitForTxCompletion( client: ReturnType, txId: string, label: string, ) { const terminalStates = new Set([\ "COMPLETE",\ "CONFIRMED",\ "FAILED",\ "DENIED",\ "CANCELLED",\ ]); while (true) { const { data } = await client.getTransaction({ id: txId }); const state = data?.transaction?.state; if (state && terminalStates.has(state)) { console.log(`${label} final state: ${state}`); if (state !== "COMPLETE" && state !== "CONFIRMED") { throw new Error(`${label} failed with state ${state}`); } return; } await new Promise((resolve) => setTimeout(resolve, 3000)); } } async function main() { const source = SUPPORTED_EVM_CHAINS[SOURCE_CHAIN]; const destination = SUPPORTED_EVM_CHAINS[DESTINATION_CHAIN]; const amount = parseUsdc(TRANSFER_AMOUNT_USDC); console.log( `Signing burn intent for ${TRANSFER_AMOUNT_USDC} USDC from ${source.label} to ${destination.label}...`, ); // The burn intent describes what Gateway burns on Arc and mints on Ethereum. const burnIntent = { maxBlockHeight: MAX_BLOCK_HEIGHT, maxFee: MAX_FEE, spec: { version: 1, sourceDomain: source.domainId, destinationDomain: destination.domainId, sourceContract: GATEWAY_WALLET_ADDRESS, destinationContract: GATEWAY_MINTER_ADDRESS, sourceToken: source.usdcAddress, destinationToken: destination.usdcAddress, sourceDepositor: process.env.DEPOSITOR_ADDRESS!, destinationRecipient: process.env.RECIPIENT_ADDRESS!, sourceSigner: process.env.DEPOSITOR_ADDRESS!, destinationCaller: "0x0000000000000000000000000000000000000000", value: amount, salt: `0x${randomBytes(32).toString("hex")}`, hookData: "0x", }, }; const typedData = { types: { EIP712Domain, TransferSpec, BurnIntent }, domain, primaryType: "BurnIntent" as const, message: { ...burnIntent, spec: { ...burnIntent.spec, sourceContract: addressToBytes32(burnIntent.spec.sourceContract), destinationContract: addressToBytes32( burnIntent.spec.destinationContract, ), sourceToken: addressToBytes32(burnIntent.spec.sourceToken), destinationToken: addressToBytes32(burnIntent.spec.destinationToken), sourceDepositor: addressToBytes32(burnIntent.spec.sourceDepositor), destinationRecipient: addressToBytes32( burnIntent.spec.destinationRecipient, ), sourceSigner: addressToBytes32(burnIntent.spec.sourceSigner), destinationCaller: addressToBytes32(burnIntent.spec.destinationCaller), }, }, }; const client = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY!, entitySecret: process.env.CIRCLE_ENTITY_SECRET!, }); // Sign the EIP-712 burn intent with the Arc source wallet. const signatureResponse = await client.signTypedData({ walletAddress: process.env.DEPOSITOR_ADDRESS!, blockchain: source.walletChain, data: stringifyWithBigints(typedData), }); const signature = signatureResponse.data?.signature; if (!signature) throw new Error("Failed to sign the burn intent"); // Gateway accepts an array of burn intents, so you can batch multiple burns into one transfer request. const gatewayResponse = await fetch( "https://gateway-api-testnet.circle.com/v1/transfer", { method: "POST", headers: { "Content-Type": "application/json" }, body: stringifyWithBigints([\ {\ burnIntent: typedData.message,\ signature,\ },\ ]), }, ); if (!gatewayResponse.ok) { throw new Error(`Gateway API error: ${gatewayResponse.status}`); } const gatewayJson = (await gatewayResponse.json()) as { attestation: string; signature: string; }; console.log( "Gateway accepted the burn intent and returned a mint attestation.", ); // Mint on Ethereum Sepolia with the attestation returned by Gateway. const mintTx = await client.createContractExecutionTransaction({ walletAddress: process.env.DEPOSITOR_ADDRESS!, blockchain: destination.walletChain, contractAddress: GATEWAY_MINTER_ADDRESS, abiFunctionSignature: "gatewayMint(bytes,bytes)", abiParameters: [gatewayJson.attestation, gatewayJson.signature], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); const mintTxId = mintTx.data?.id; if (!mintTxId) throw new Error("Failed to create mint transaction"); await waitForTxCompletion(client, mintTxId, "Gateway mint"); console.log(`Gateway mint confirmed on ${destination.label}: ${mintTxId}`); } void main(); See all 197 lines ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#4-2-run-the-transfer-script) 4.2. Run the transfer script Run the transfer script to transfer 1 USDC from your Arc Gateway balance to Ethereum Sepolia. npm run transfer [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#prerequisites-2) Prerequisites --------------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. A private key for an EVM wallet you control 2. Testnet USDC and native tokens on Arc Testnet 3. Testnet native tokens on Ethereum Sepolia for the destination mint [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-1-set-up-your-project-2) Step 1. Set up your project ------------------------------------------------------------------------------------------------------------------------------ In this step, you create the project, install viem, and configure your environment. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#1-1-create-the-project-and-install-dependencies-2) 1.1. Create the project and install dependencies mkdir arc-gateway-balance cd arc-gateway-balance npm init -y npm pkg set type=module npm pkg set scripts.deposit="tsx --env-file=.env deposit.ts" npm pkg set scripts.transfer="tsx --env-file=.env transfer.ts" npm pkg set scripts.balances="tsx --env-file=.env balances.ts" npm install viem npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#1-2-configure-typescript-optional-2) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#1-3-set-environment-variables-2) 1.3. Set environment variables Create a `.env` file in the project directory: .env EVM_PRIVATE_KEY=0xYOUR_PRIVATE_KEY RECIPIENT_ADDRESS=YOUR_ETHEREUM_ADDRESS * `EVM_PRIVATE_KEY` is the `0x`\-prefixed private key for the EVM wallet that deposits from Arc and signs the Gateway burn intent. * `RECIPIENT_ADDRESS` is the Ethereum Sepolia address that receives the minted USDC. The `npm run` commands in this tutorial load variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-2-fund-your-wallet) Step 2. Fund your wallet ---------------------------------------------------------------------------------------------------------------------- In this step, you prepare the same EVM account on Arc Testnet and Ethereum Sepolia for the Gateway flow. If you already have the same EVM account funded on both chains, skip ahead to the [deposit step](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-3-deposit-usdc-into-a-gateway-balance-on-arc-2) . ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#2-1-fund-arc-and-ethereum) 2.1. Fund Arc and Ethereum To follow this flow: * fund the Arc Testnet wallet with testnet USDC and native tokens * fund the same address on Ethereum Sepolia with native tokens for the destination mint Use the [Circle Faucet](https://faucet.circle.com/) for Arc Testnet USDC and the [Ethereum Sepolia faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia) for destination gas. [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-3-deposit-usdc-into-a-gateway-balance-on-arc-2) Step 3. Deposit USDC into a Gateway balance on Arc ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In this step, you deposit USDC from Arc Testnet into your unified Gateway balance. The script fixes the source chain to Arc Testnet, but the `SUPPORTED_EVM_CHAINS` object shows the broader EVM support you can extend later. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#3-1-create-the-shared-config-file-2) 3.1. Create the shared config file config.ts import { parseUnits } from "viem"; import { arcTestnet, arbitrumSepolia, avalancheFuji, baseSepolia, hyperliquidEvmTestnet, optimismSepolia, polygonAmoy, seiTestnet, sepolia, sonicTestnet, unichainSepolia, worldchainSepolia, } from "viem/chains"; export const GATEWAY_WALLET_ADDRESS = "0x0077777d7EBA4688BDeF3E311b846F25870A19B9"; export const GATEWAY_MINTER_ADDRESS = "0x0022222ABE238Cc2C7Bb1f21003F0a260052475B"; export const SOURCE_CHAIN = "arcTestnet" as const; export const DESTINATION_CHAIN = "sepolia" as const; export const DEPOSIT_AMOUNT = parseUnits("2", 6); export const TRANSFER_VALUE = parseUnits("1", 6); export const SUPPORTED_EVM_CHAINS = { sepolia: { label: "Ethereum Sepolia", chain: sepolia, domainId: 0, usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", }, baseSepolia: { label: "Base Sepolia", chain: baseSepolia, domainId: 6, usdcAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", }, avalancheFuji: { label: "Avalanche Fuji", chain: avalancheFuji, domainId: 1, usdcAddress: "0x5425890298aed601595a70AB815c96711a31Bc65", }, arcTestnet: { label: "Arc Testnet", chain: arcTestnet, domainId: 26, usdcAddress: "0x3600000000000000000000000000000000000000", }, arbitrumSepolia: { label: "Arbitrum Sepolia", chain: arbitrumSepolia, domainId: 3, usdcAddress: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", }, optimismSepolia: { label: "OP Sepolia", chain: optimismSepolia, domainId: 2, usdcAddress: "0x5fd84259d66Cd46123540766Be93DFE6D43130D7", }, polygonAmoy: { label: "Polygon Amoy", chain: polygonAmoy, domainId: 7, usdcAddress: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582", }, hyperliquidEvmTestnet: { label: "HyperEVM Testnet", chain: hyperliquidEvmTestnet, domainId: 19, usdcAddress: "0x2B3370eE501B4a559b57D449569354196457D8Ab", }, seiTestnet: { label: "Sei Atlantic", chain: seiTestnet, domainId: 16, usdcAddress: "0x4fCF1784B31630811181f670Aea7A7bEF803eaED", }, sonicTestnet: { label: "Sonic Testnet", chain: sonicTestnet, domainId: 13, usdcAddress: "0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51", }, unichainSepolia: { label: "Unichain Sepolia", chain: unichainSepolia, domainId: 10, usdcAddress: "0x31d0220469e10c4E71834a79b1f276d740d3768F", }, worldchainSepolia: { label: "World Chain Sepolia", chain: worldchainSepolia, domainId: 14, usdcAddress: "0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88", }, } as const; See all 99 lines ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#3-2-create-the-deposit-script-2) 3.2. Create the deposit script The main logic performs two key actions: * **Approve USDC transfers**: It calls the `approve` method on the USDC contract to allow the Gateway Wallet contract to transfer USDC from your wallet. * **Deposit USDC into Gateway**: After receiving the approval transaction hash, it calls the `deposit` method on the Gateway Wallet contract. deposit.ts import { createPublicClient, createWalletClient, erc20Abi, getContract, http, } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { DEPOSIT_AMOUNT, GATEWAY_WALLET_ADDRESS, SOURCE_CHAIN, SUPPORTED_EVM_CHAINS, } from "./config.js"; async function main() { const account = privateKeyToAccount( process.env.EVM_PRIVATE_KEY as `0x${string}`, ); const config = SUPPORTED_EVM_CHAINS[SOURCE_CHAIN]; console.log(`Approving 2 USDC on ${config.label}...`); // Reuse the same private key on Arc and Ethereum so the flow stays easy to follow. const publicClient = createPublicClient({ chain: config.chain, transport: http(), }); const walletClient = createWalletClient({ account, chain: config.chain, transport: http(), }); const usdc = getContract({ address: config.usdcAddress as `0x${string}`, abi: erc20Abi, client: { public: publicClient, wallet: walletClient }, }); const gatewayWallet = getContract({ address: GATEWAY_WALLET_ADDRESS, abi: [\ {\ type: "function",\ name: "deposit",\ inputs: [\ { name: "token", type: "address" },\ { name: "value", type: "uint256" },\ ],\ outputs: [],\ stateMutability: "nonpayable",\ },\ ], client: { public: publicClient, wallet: walletClient }, }); // Gateway deposits are a two-step flow: approve USDC, then call deposit(). const approvalTx = await usdc.write.approve( [GATEWAY_WALLET_ADDRESS, DEPOSIT_AMOUNT], { account }, ); await publicClient.waitForTransactionReceipt({ hash: approvalTx }); console.log(`USDC approve confirmed on ${config.label}: ${approvalTx}`); console.log(`Depositing 2 USDC into Gateway on ${config.label}...`); const depositTx = await gatewayWallet.write.deposit( [config.usdcAddress as `0x${string}`, DEPOSIT_AMOUNT], { account }, ); await publicClient.waitForTransactionReceipt({ hash: depositTx }); console.log(`Gateway deposit confirmed on ${config.label}: ${depositTx}`); } void main(); Run the deposit script to deposit USDC from Arc Testnet into your Gateway balance. npm run deposit Wait for the [required number of block confirmations](https://developers.circle.com/gateway/references/supported-blockchains#required-block-confirmations) . Once the Arc deposit transaction is final, the funds become available in your Gateway balance. Note that for certain chains, finality may take up to 20 minutes to be reached. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#3-3-check-the-gateway-balances-2) 3.3. Check the Gateway balances Create a balance script that queries your unified Gateway balance across the configured EVM domains. balances.ts import { privateKeyToAccount } from "viem/accounts"; import { SUPPORTED_EVM_CHAINS } from "./config.js"; async function main() { const account = privateKeyToAccount( process.env.EVM_PRIVATE_KEY as `0x${string}`, ); console.log(`Gateway balances for ${account.address}:`); // Query every configured Gateway domain to inspect the unified balance. const response = await fetch( "https://gateway-api-testnet.circle.com/v1/balances", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: "USDC", sources: Object.values(SUPPORTED_EVM_CHAINS).map((chain) => ({ domain: chain.domainId, depositor: account.address, })), }), }, ); const result = (await response.json()) as { balances: Array<{ domain: number; balance: string }>; }; for (const balance of result.balances) { const chain = Object.values(SUPPORTED_EVM_CHAINS).find( (item) => item.domainId === balance.domain, )?.label ?? `Domain ${balance.domain}`; console.log(`${chain}: ${balance.balance} USDC`); } } void main(); Run the balance script to check the balances on the Gateway Wallet. npm run balances [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#step-4-transfer-usdc-from-the-arc-gateway-balance-to-ethereum-2) Step 4. Transfer USDC from the Arc Gateway balance to Ethereum ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In this step, you burn from the Arc Gateway balance and mint on Ethereum Sepolia. The same script shape works for other supported EVM destinations by changing `DESTINATION_CHAIN`. ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#4-1-create-the-transfer-script-2) 4.1. Create the transfer script This example submits one burn intent for clarity. You can also submit multiple burn intents to the Gateway API in a single request and receive a single attestation response to use when minting on the destination chain. transfer.ts import { randomBytes } from "node:crypto"; import { createPublicClient, createWalletClient, getContract, http, maxUint256, pad, zeroAddress, } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { DESTINATION_CHAIN, GATEWAY_MINTER_ADDRESS, GATEWAY_WALLET_ADDRESS, SOURCE_CHAIN, SUPPORTED_EVM_CHAINS, TRANSFER_VALUE, } from "./config.js"; const MAX_FEE = 2_010000n; const domain = { name: "GatewayWallet", version: "1" }; const EIP712Domain = [\ { name: "name", type: "string" },\ { name: "version", type: "string" },\ ] as const; const TransferSpec = [\ { name: "version", type: "uint32" },\ { name: "sourceDomain", type: "uint32" },\ { name: "destinationDomain", type: "uint32" },\ { name: "sourceContract", type: "bytes32" },\ { name: "destinationContract", type: "bytes32" },\ { name: "sourceToken", type: "bytes32" },\ { name: "destinationToken", type: "bytes32" },\ { name: "sourceDepositor", type: "bytes32" },\ { name: "destinationRecipient", type: "bytes32" },\ { name: "sourceSigner", type: "bytes32" },\ { name: "destinationCaller", type: "bytes32" },\ { name: "value", type: "uint256" },\ { name: "salt", type: "bytes32" },\ { name: "hookData", type: "bytes" },\ ] as const; const BurnIntent = [\ { name: "maxBlockHeight", type: "uint256" },\ { name: "maxFee", type: "uint256" },\ { name: "spec", type: "TransferSpec" },\ ] as const; function addressToBytes32(address: string) { return pad(address.toLowerCase() as `0x${string}`, { size: 32 }); } function stringifyWithBigints(value: T): string { return JSON.stringify(value, (_key, current) => typeof current === "bigint" ? current.toString() : current, ); } async function main() { const account = privateKeyToAccount( process.env.EVM_PRIVATE_KEY as `0x${string}`, ); const source = SUPPORTED_EVM_CHAINS[SOURCE_CHAIN]; const destination = SUPPORTED_EVM_CHAINS[DESTINATION_CHAIN]; console.log( `Signing burn intent for 1 USDC from ${source.label} to ${destination.label}...`, ); // The burn intent describes what Gateway burns on Arc and mints on Ethereum. const burnIntent = { maxBlockHeight: maxUint256, maxFee: MAX_FEE, spec: { version: 1, sourceDomain: source.domainId, destinationDomain: destination.domainId, sourceContract: GATEWAY_WALLET_ADDRESS, destinationContract: GATEWAY_MINTER_ADDRESS, sourceToken: source.usdcAddress, destinationToken: destination.usdcAddress, sourceDepositor: account.address, destinationRecipient: process.env.RECIPIENT_ADDRESS!, sourceSigner: account.address, destinationCaller: zeroAddress, value: TRANSFER_VALUE, salt: `0x${randomBytes(32).toString("hex")}` as `0x${string}`, hookData: "0x" as `0x${string}`, }, }; const typedData = { types: { EIP712Domain, TransferSpec, BurnIntent }, domain, primaryType: "BurnIntent" as const, message: { ...burnIntent, spec: { ...burnIntent.spec, sourceContract: addressToBytes32(burnIntent.spec.sourceContract), destinationContract: addressToBytes32( burnIntent.spec.destinationContract, ), sourceToken: addressToBytes32(burnIntent.spec.sourceToken), destinationToken: addressToBytes32(burnIntent.spec.destinationToken), sourceDepositor: addressToBytes32(burnIntent.spec.sourceDepositor), destinationRecipient: addressToBytes32( burnIntent.spec.destinationRecipient, ), sourceSigner: addressToBytes32(burnIntent.spec.sourceSigner), destinationCaller: addressToBytes32(burnIntent.spec.destinationCaller), }, }, }; // Sign the burn intent locally with the Arc source-chain private key. const signature = await account.signTypedData(typedData); // Gateway accepts an array of burn intents, so you can batch multiple burns into one transfer request. const gatewayResponse = await fetch( "https://gateway-api-testnet.circle.com/v1/transfer", { method: "POST", headers: { "Content-Type": "application/json" }, body: stringifyWithBigints([\ {\ burnIntent: typedData.message,\ signature,\ },\ ]), }, ); if (!gatewayResponse.ok) { throw new Error(`Gateway API error: ${gatewayResponse.status}`); } const gatewayJson = (await gatewayResponse.json()) as { attestation: `0x${string}`; signature: `0x${string}`; }; console.log( "Gateway accepted the burn intent and returned a mint attestation.", ); // Mint on Ethereum Sepolia with the attestation returned by Gateway. const publicClient = createPublicClient({ chain: destination.chain, transport: http(), }); const walletClient = createWalletClient({ account, chain: destination.chain, transport: http(), }); const minter = getContract({ address: GATEWAY_MINTER_ADDRESS, abi: [\ {\ type: "function",\ name: "gatewayMint",\ inputs: [\ { name: "attestationPayload", type: "bytes" },\ { name: "signature", type: "bytes" },\ ],\ outputs: [],\ stateMutability: "nonpayable",\ },\ ], client: { public: publicClient, wallet: walletClient }, }); const mintTx = await minter.write.gatewayMint( [gatewayJson.attestation, gatewayJson.signature], { account }, ); await publicClient.waitForTransactionReceipt({ hash: mintTx }); console.log(`Gateway mint confirmed on ${destination.label}: ${mintTx}`); } void main(); See all 187 lines ### [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#4-2-run-the-transfer-script-2) 4.2. Run the transfer script Run the transfer script to transfer 1 USDC from your Arc Gateway balance to Ethereum Sepolia. npm run transfer [​](https://docs.arc.network/arc/tutorials/access-usdc-crosschain#summary) Summary ------------------------------------------------------------------------------------- After completing this tutorial, you have: * created or prepared the wallets needed for the Arc-to-Ethereum flow * deposited USDC from Arc Testnet into a unified Gateway balance * checked the Gateway balance across supported EVM domains * transferred that Arc Gateway balance to Ethereum Sepolia Was this page helpful? YesNo [Transfer USDC or EURC](https://docs.arc.network/arc/tutorials/transfer-usdc-or-eurc) [Interact with contracts](https://docs.arc.network/arc/tutorials/interact-with-contracts) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Deploy contracts - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/deploy-contracts#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Quickstarts Deploy contracts [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [Prerequisites](https://docs.arc.network/arc/tutorials/deploy-contracts#prerequisites) * [Step 1. Set up your project](https://docs.arc.network/arc/tutorials/deploy-contracts#step-1-set-up-your-project) * [1.1. Create the project and install dependencies](https://docs.arc.network/arc/tutorials/deploy-contracts#1-1-create-the-project-and-install-dependencies) * [1.2. Configure TypeScript (optional)](https://docs.arc.network/arc/tutorials/deploy-contracts#1-2-configure-typescript-optional) * [1.3. Set environment variables](https://docs.arc.network/arc/tutorials/deploy-contracts#1-3-set-environment-variables) * [Step 2. Set up your wallet](https://docs.arc.network/arc/tutorials/deploy-contracts#step-2-set-up-your-wallet) * [2.1. Create a wallet](https://docs.arc.network/arc/tutorials/deploy-contracts#2-1-create-a-wallet) * [Summary](https://docs.arc.network/arc/tutorials/deploy-contracts#summary) This tutorial guides you through deploying smart contracts on Arc Testnet with [Circle Contracts](https://developers.circle.com/contracts/scp-templates-overview) . You’ll create a [Circle Dev-Controlled SCA Wallet](https://developers.circle.com/wallets/dev-controlled) , then deploy pre-audited contract templates (ERC-20, ERC-721, ERC-1155, Airdrop). With SCA wallets, [Circle Gas Station](https://developers.circle.com/wallets/gas-station) automatically sponsors your transaction fees on Arc Testnet. These pre-audited templates represent building blocks: ERC-20 for money and liquidity, ERC-721 for identity and unique rights, ERC-1155 for scalable financial instruments, and Airdrops for distributing incentives. To learn more about available templates, visit the [Templates Overview](https://developers.circle.com/contracts/scp-templates-overview) to review all templates and their options. [​](https://docs.arc.network/arc/tutorials/deploy-contracts#prerequisites) Prerequisites ------------------------------------------------------------------------------------------- To complete this tutorial, you need: 1. [Node.js v22+](https://nodejs.org/) installed 2. **Circle Developer Account** - [Sign up](https://console.circle.com/) on the Developer Console 3. **API Key** - Create in the Console: **Keys → Create a key → API key → Standard Key** 4. **Entity Secret** - Required to initialize the Circle Dev-Controlled Wallets SDK. Learn how to [register your Entity Secret](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-1-set-up-your-project) Step 1. Set up your project ---------------------------------------------------------------------------------------------------------------------- Before deploying any template, you need a working project and a funded dev-controlled wallet on Arc Testnet. Complete the steps in this section once. Then reuse the same wallet and credentials across all template deployments below. ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#1-1-create-the-project-and-install-dependencies) 1.1. Create the project and install dependencies Create a new directory. Navigate to it and start a new project with default settings. Node.js Python mkdir hello-arc cd hello-arc npm init -y npm pkg set type=module # Add run scripts for wallet creation and contract deployment npm pkg set scripts.create-wallet="tsx --env-file=.env create-wallet.ts" npm pkg set scripts.deploy-erc20="tsx --env-file=.env deploy-erc20.ts" npm pkg set scripts.deploy-erc721="tsx --env-file=.env deploy-erc721.ts" npm pkg set scripts.deploy-erc1155="tsx --env-file=.env deploy-erc1155.ts" npm pkg set scripts.deploy-airdrop="tsx --env-file=.env deploy-airdrop.ts" In the project directory, install the [Circle Dev-Controlled Wallets SDK](https://developers.circle.com/wallets/dev-controlled) and the [Circle Contracts SDK](https://developers.circle.com/sdks) . Dev-Controlled Wallets are Circle-managed wallets that your app controls via APIs. You can deploy contracts and submit transactions without managing private keys directly. You can also call the [Circle Wallets API](https://developers.circle.com/api-reference/wallets/) and [Circle Contracts API](https://developers.circle.com/api-reference/contracts/) directly if you can’t use the SDKs in your project. Node.js Python npm install @circle-fin/developer-controlled-wallets @circle-fin/smart-contract-platform npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) Create a `tsconfig.json` file: Node.js npx tsc --init Then, edit the `tsconfig.json` file: Node.js cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#1-3-set-environment-variables) 1.3. Set environment variables Create a `.env` file in the project directory with your Circle credentials. Replace these placeholders with your own credentials: .env CIRCLE_API_KEY=YOUR_API_KEY CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET CIRCLE_WEB3_API_KEY=YOUR_API_KEY * `CIRCLE_API_KEY` is your Circle Developer API key for Wallets and Contracts API requests. * `CIRCLE_ENTITY_SECRET` is your registered entity secret used to authorize developer-controlled wallet operations. * `CIRCLE_WEB3_API_KEY` is the Python SDK compatibility variable and should use the same value as `CIRCLE_API_KEY`. The npm run commands in this tutorial load variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. This tutorial adds runtime values such as wallet IDs, transaction IDs, and contract IDs later in the flow. Keep those derived values aligned with the script outputs as you progress through the deployment steps. [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-2-set-up-your-wallet) Step 2. Set up your wallet -------------------------------------------------------------------------------------------------------------------- In this step, you create a dev-controlled wallet and fund it for contract deployment on Arc Testnet. If you already have a funded Arc Testnet dev-controlled wallet, skip to [the contract templates section](https://docs.arc.network/arc/tutorials/deploy-contracts#deploy-an-erc-20-contract) . ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#2-1-create-a-wallet) 2.1. Create a wallet Import the Wallets SDK and start the client with your API key and Entity Secret. Dev-controlled wallets are created in a [wallet set](https://developers.circle.com/wallets/dev-controlled/create-your-first-wallet#1-create-a-wallet-set) . The wallet set is the source from which wallet keys are derived. create-wallet.ts create\_wallet.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const client = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); // Create a wallet set const walletSetResponse = await client.createWalletSet({ name: "Wallet Set 1", }); // Create a wallet on Arc Testnet const walletsResponse = await client.createWallets({ blockchains: ["ARC-TESTNET"], count: 1, walletSetId: walletSetResponse.data?.walletSet?.id ?? "", accountType: "SCA", }); console.log(JSON.stringify(walletsResponse.data, null, 2)); **Run the script:** Node.js Python npm run create-wallet **Response:** If you’re calling the API directly, you’ll need two requests. One to [create the wallet set](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-wallet-set) . One to [create the wallet](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-wallet) .Be sure to replace the [Entity Secret ciphertext](https://developers.circle.com/wallets/dev-controlled/entity-secret-management#what-is-an-entity-secret-ciphertext) and the idempotency key in your request. If you’re using the SDKs, this is handled for you. You should now have a newly created dev-controlled wallet. The API response will look similar to the following: { "wallets": [\ {\ "id": "45692c3e-2ffa-5c5b-a99c-61366939114c",\ "state": "LIVE",\ "walletSetId": "ee58db40-22b4-55cb-9ce6-3444cb6efd2f",\ "custodyType": "DEVELOPER",\ "address": "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758",\ "blockchain": "ARC-TESTNET",\ "accountType": "SCA",\ "updateDate": "2026-01-20T09:39:16Z",\ "createDate": "2026-01-20T09:39:16Z",\ "scaCore": "circle_6900_singleowner_v3"\ }\ ] } **Why SCA wallets?** Smart Contract Accounts (SCA) on Arc Testnet work with [Gas Station](https://developers.circle.com/wallets/gas-station) to automatically sponsor transaction fees. Learn more about [Gas Station policies and setup](https://developers.circle.com/wallets/gas-station) . * * * * ERC-20 * ERC-721 * ERC-1155 * Airdrop [​](https://docs.arc.network/arc/tutorials/deploy-contracts#deploy-an-erc-20-contract) Deploy an ERC-20 contract ------------------------------------------------------------------------------------------------------------------- ERC-20 is the standard for fungible tokens. Use this template for tokenized assets, treasury instruments, governance tokens, or programmable money. ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-3-prepare-for-deployment) Step 3: Prepare for deployment #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-1-get-your-wallet-information) 3.1. Get your wallet information Retrieve your wallet ID from Step 2. Ensure: * Wallet custody type is **Dev-Controlled** * Blockchain is **Arc Testnet** * Account type is **SCA** (Smart Contract Account, recommended for Gas Station compatibility) Note your wallet’s address for subsequent steps. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-2-understand-deployment-parameters) 3.2. Understand deployment parameters | Parameter | Description | | --- | --- | | `idempotencyKey` | A unique value to prevent duplicate requests. | | `name` | The offchain contract name (visible in Circle Console only). Use `MyTokenContract`. | | `walletId` | The ID of the wallet deploying the contract. Use your dev-controlled wallet ID. | | `templateId` | The template identifier. Use `a1b74add-23e0-4712-88d1-6b3009e85a86` for ERC-20. See [Templates](https://developers.circle.com/contracts/scp-templates-overview)
. | | `blockchain` | The network to deploy onto. Use `ARC-TESTNET`. | | `entitySecretCiphertext` | The re-encrypted entity secret. See [Entity Secret Management](https://developers.circle.com/wallets/dev-controlled/entity-secret-management)
. | | `feeLevel` | The fee level for transaction processing. Use `MEDIUM`. | | `templateParameters` | The onchain initialization parameters (see below). | #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-3-template-parameters) 3.3. Template parameters **Required Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `name` | String | The onchain contract name. Use `MyToken`. | | `defaultAdmin` | String | The address with administrator permissions. Use your Dev-Controlled Wallet address. | | `primarySaleRecipient` | String | The address that receives proceeds from first-time sales. Use your wallet address. | **Optional Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `symbol` | String | The token symbol (for example, `MTK`). | | `platformFeeRecipient` | String | The address that receives platform fees from sales. Set this when implementing platform fee revenue share. | | `platformFeePercent` | Float | The platform fee percentage as decimal (for example, `0.1` for 10%). Requires `platformFeeRecipient`. | | `contractUri` | String | The URL for the contract metadata. | | `trustedForwarders` | Strings\[\] | A list of addresses that can forward ERC2771 meta-transactions to this contract. | ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-4-deploy-the-smart-contract) Step 4: Deploy the smart contract Deploy by making a request to [`POST /templates/{id}/deploy`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/deploy-contract-template) : deploy-erc20.ts deploy\_erc20.py cURL import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const response = await circleContractSdk.deployContractTemplate({ id: "a1b74add-23e0-4712-88d1-6b3009e85a86", blockchain: "ARC-TESTNET", name: "MyTokenContract", walletId: process.env.WALLET_ID, templateParameters: { name: "MyToken", symbol: "MTK", defaultAdmin: process.env.WALLET_ADDRESS, primarySaleRecipient: process.env.WALLET_ADDRESS, }, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(response.data, null, 2)); **Run the script:** Node.js Python npm run deploy-erc20 **Response:** { "contractIds": ["019c053d-1ed1-772b-91a8-6970003dad8d"], "transactionId": "5b6185b2-f9a1-5645-9db2-ca5d9a330794" } A successful response indicates deployment has been **initiated**, not completed. Use the `transactionId` to check the deployment status in the next step. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-1-check-deployment-status) 4.1. Check deployment status You can check the status of the deployment from the [Circle Developer Console](https://console.circle.com/smart-contracts/contracts) or by calling [`GET /transactions/{id}`](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/get-transaction) .After running the deployment script, copy the `transactionId` from the response and update your `.env` file with `TRANSACTION_ID={your-transaction-id}`. Then run the check-transaction script to verify deployment status. check-transaction.ts check\_transaction.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const transactionResponse = await circleDeveloperSdk.getTransaction({ id: process.env.TRANSACTION_ID!, }); console.log(JSON.stringify(transactionResponse.data, null, 2)); **Run the script:** Node.js Python npm pkg set scripts.check-transaction="tsx --env-file=.env check-transaction.ts" npm run check-transaction Transaction status may show PENDING immediately after deployment. Wait 10-30 seconds and re-run check-transaction to see COMPLETE status. **Response:** { "transaction": { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "blockchain": "ARC-TESTNET", "walletId": "45692c3e-2ffa-5c5b-a99c-61366939114c", "sourceAddress": "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758", "contractAddress": "0x281156899e5bd6fecf1c0831ee24894eeeaea2f8", "transactionType": "OUTBOUND", "custodyType": "DEVELOPER", "state": "COMPLETE", "amounts": [], "nfts": null, "txHash": "0x3bfbab5d5ce0d1a5d682cbc742d3940cf59db0369d173b71ba2a3b8f43bfbcb1", "blockHash": "0x7d12148f9331556b31f84f58a41b7ff16eaaa47940f9e86733037d7ab74d858e", "blockHeight": 23686153, "userOpHash": "0x66befac1a371fcdddf1566215e4677127e111dff9253f306f7096fed8642a208", "networkFee": "0.044628774800664", "firstConfirmDate": "2026-01-26T08:59:56Z", "operation": "CONTRACT_EXECUTION", "feeLevel": "MEDIUM", "estimatedFee": { "gasLimit": "500797", "networkFee": "0.16506442157883425", "baseFee": "160", "priorityFee": "9.60345525", "maxFee": "329.60345525" }, "refId": "", "abiFunctionSignature": "mintTo(address,uint256)", "abiParameters": [\ "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758",\ "1000000000000000000"\ ], "createDate": "2026-01-26T08:59:54Z", "updateDate": "2026-01-26T08:59:56Z" } } #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-2-get-the-contract-address) 4.2. Get the contract address After deployment completes, retrieve the contract address using [`GET /contracts/{id}`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/get-contract) .After deployment completes, copy the `contractIds[0]` from the deployment response and update your `.env` file with `CONTRACT_ID={your-contract-id}`. Then run the get-contract script to retrieve the contract address. get-contract.ts get\_contract.py import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const contractResponse = await circleContractSdk.getContract({ id: process.env.CONTRACT_ID!, }); console.log(JSON.stringify(contractResponse.data, null, 2)); **Run the script:** Node.js Python npm pkg set scripts.get-contract="tsx --env-file=.env get-contract.ts" npm run get-contract **Response:** { "contract": { "id": "b7c35372-ce69-4ccd-bfaa-504c14634f0d", "contractAddress": "0x1234567890abcdef1234567890abcdef12345678", "blockchain": "ARC-TESTNET", "status": "COMPLETE" } } Once your contract is deployed, you can interact with it from your application. You’ll be able to view the contract both in the [Circle Developer Console](https://console.circle.com/smart-contracts/contracts) and on the [Arc Testnet Explorer](https://testnet.arcscan.app/) . **Initial Supply:** The contract starts with 0 token supply at deployment. Use the `mintTo` function to create tokens and assign them to addresses as needed. * * * [​](https://docs.arc.network/arc/tutorials/deploy-contracts#deploy-an-erc-721-contract) Deploy an ERC-721 contract --------------------------------------------------------------------------------------------------------------------- ERC-721 is the standard for unique digital assets. Use this template for ownership certificates, tokenized assets, unique financial instruments, or distinct asset representation. ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-3-prepare-for-deployment-2) Step 3: Prepare for deployment #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-1-get-your-wallet-information-2) 3.1. Get your wallet information Retrieve your wallet ID from Step 2. Ensure: * Wallet custody type is **Dev-Controlled** * Blockchain is **Arc Testnet** * Account type is **SCA** (Smart Contract Account, recommended for Gas Station compatibility) Note your wallet’s address for subsequent steps. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-2-understand-deployment-parameters-2) 3.2. Understand deployment parameters | Parameter | Description | | --- | --- | | `idempotencyKey` | A unique value to prevent duplicate requests. | | `name` | The offchain contract name (visible in Circle Console only). Use `MyTokenContract`. | | `walletId` | The ID of the wallet deploying the contract. Use your dev-controlled wallet ID. | | `templateId` | The template identifier. Use `76b83278-50e2-4006-8b63-5b1a2a814533` for ERC-721. See [Templates](https://developers.circle.com/contracts/scp-templates-overview)
. | | `blockchain` | The network to deploy onto. Use `ARC-TESTNET`. | | `entitySecretCiphertext` | The re-encrypted entity secret. See [Entity Secret Management](https://developers.circle.com/wallets/dev-controlled/entity-secret-management)
. | | `feeLevel` | The fee level for transaction processing. Use `MEDIUM`. | | `templateParameters` | The onchain initialization parameters (see below). | #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-3-template-parameters-2) 3.3. Template parameters **Required Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `name` | String | The onchain contract name. Use `MyToken`. | | `defaultAdmin` | String | The address with administrator permissions. Use your Dev-Controlled Wallet address. | | `primarySaleRecipient` | String | The address for first-time sale proceeds. Use your Dev-Controlled Wallet address. | | `royaltyRecipient` | String | The address for secondary sale royalties. Use your Dev-Controlled Wallet address. | | `royaltyPercent` | Float | The royalty share as a decimal (for example, `0.01` for 1%). Use `0.01`. | **Optional Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `symbol` | String | The token symbol (for example, `MTK`). | | `platformFeeRecipient` | String | The address that receives platform fees from sales. Set this when implementing platform fee revenue share. | | `platformFeePercent` | Float | The platform fee percentage as decimal (for example, `0.1` for 10%). Requires `platformFeeRecipient`. | | `contractUri` | String | The URL for the contract metadata. | | `trustedForwarders` | Strings\[\] | A list of addresses that can forward ERC2771 meta-transactions to this contract. | ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-4-deploy-the-smart-contract-2) Step 4: Deploy the smart contract Deploy by making a request to [`POST /templates/{id}/deploy`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/deploy-contract-template) : deploy-erc721.ts deploy\_erc721.py cURL import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const response = await circleContractSdk.deployContractTemplate({ id: "76b83278-50e2-4006-8b63-5b1a2a814533", blockchain: "ARC-TESTNET", name: "MyTokenContract", walletId: process.env.WALLET_ID, templateParameters: { name: "MyToken", symbol: "MTK", defaultAdmin: process.env.WALLET_ADDRESS, primarySaleRecipient: process.env.WALLET_ADDRESS, royaltyRecipient: process.env.WALLET_ADDRESS, royaltyPercent: 0.01, }, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(response.data, null, 2)); **Run the script:** Node.js Python npm run deploy-erc721 **Response:** { "contractIds": ["019c053d-1ed1-772b-91a8-6970003dad8d"], "transactionId": "5b6185b2-f9a1-5645-9db2-ca5d9a330794" } A successful response indicates deployment has been **initiated**, not completed. Use the `transactionId` to check the deployment status in the next step. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-1-check-deployment-status-2) 4.1. Check deployment status Verify deployment with [`GET /transactions/{id}`](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/get-transaction) .After running the deployment script, copy the `transactionId` from the response and update your `.env` file with `TRANSACTION_ID={your-transaction-id}`. Then run the check-transaction script to verify deployment status. check-transaction.ts check\_transaction.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const transactionResponse = await circleDeveloperSdk.getTransaction({ id: process.env.TRANSACTION_ID!, }); console.log(JSON.stringify(transactionResponse.data, null, 2)); **Run the script:** Node.js Python npm run check-transaction Transaction status may show PENDING immediately after deployment. Wait 10-30 seconds and re-run check-transaction to see COMPLETE status. **Response:** { "transaction": { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "blockchain": "ARC-TESTNET", "walletId": "45692c3e-2ffa-5c5b-a99c-61366939114c", "sourceAddress": "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758", "contractAddress": "0x281156899e5bd6fecf1c0831ee24894eeeaea2f8", "transactionType": "OUTBOUND", "custodyType": "DEVELOPER", "state": "COMPLETE", "amounts": [], "nfts": null, "txHash": "0x3bfbab5d5ce0d1a5d682cbc742d3940cf59db0369d173b71ba2a3b8f43bfbcb1", "blockHash": "0x7d12148f9331556b31f84f58a41b7ff16eaaa47940f9e86733037d7ab74d858e", "blockHeight": 23686153, "userOpHash": "0x66befac1a371fcdddf1566215e4677127e111dff9253f306f7096fed8642a208", "networkFee": "0.044628774800664", "firstConfirmDate": "2026-01-26T08:59:56Z", "operation": "CONTRACT_EXECUTION", "feeLevel": "MEDIUM", "estimatedFee": { "gasLimit": "500797", "networkFee": "0.16506442157883425", "baseFee": "160", "priorityFee": "9.60345525", "maxFee": "329.60345525" }, "refId": "", "abiFunctionSignature": "mintTo(address,uint256)", "abiParameters": [\ "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758",\ "1000000000000000000"\ ], "createDate": "2026-01-26T08:59:54Z", "updateDate": "2026-01-26T08:59:56Z" } } #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-2-get-the-contract-address-2) 4.2. Get the contract address After deployment completes, retrieve the contract address using [`GET /contracts/{id}`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/get-contract) .After deployment completes, copy the `contractIds[0]` from the deployment response and update your `.env` file with `CONTRACT_ID={your-contract-id}`. Then run the get-contract script to retrieve the contract address. get-contract.ts get\_contract.py import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const contractResponse = await circleContractSdk.getContract({ id: process.env.CONTRACT_ID!, }); console.log(JSON.stringify(contractResponse.data, null, 2)); **Run the script:** Node.js Python npm run get-contract **Response:** { "contract": { "id": "b7c35372-ce69-4ccd-bfaa-504c14634f0d", "contractAddress": "0x1234567890abcdef1234567890abcdef12345678", "blockchain": "ARC-TESTNET", "status": "COMPLETE" } } * * * [​](https://docs.arc.network/arc/tutorials/deploy-contracts#deploy-an-erc-1155-contract) Deploy an ERC-1155 contract ----------------------------------------------------------------------------------------------------------------------- ERC-1155 is the standard for multi-asset token management. Use this template for structured products, tiered assets, batch settlements, or managing diverse asset portfolios. ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-3-prepare-for-deployment-3) Step 3: Prepare for deployment #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-1-get-your-wallet-information-3) 3.1. Get your wallet information Retrieve your wallet ID from Step 2. Ensure: * Wallet custody type is **Dev-Controlled** * Blockchain is **Arc Testnet** * Account type is **SCA** (Smart Contract Account, recommended for Gas Station compatibility) Note your wallet’s address for subsequent steps. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-2-understand-deployment-parameters-3) 3.2. Understand deployment parameters | Parameter | Description | | --- | --- | | `idempotencyKey` | A unique value to prevent duplicate requests. | | `name` | The offchain contract name (visible in Circle Console only). Use `MyMultiTokenContract`. | | `walletId` | The ID of the wallet deploying the contract. Use your dev-controlled wallet ID. | | `templateId` | The template identifier. Use `aea21da6-0aa2-4971-9a1a-5098842b1248` for ERC-1155. See [Templates](https://developers.circle.com/contracts/scp-templates-overview)
. | | `blockchain` | The network to deploy onto. Use `ARC-TESTNET`. | | `entitySecretCiphertext` | The re-encrypted entity secret. See [Entity Secret Management](https://developers.circle.com/wallets/dev-controlled/entity-secret-management)
. | | `feeLevel` | The fee level for transaction processing. Use `MEDIUM`. | | `templateParameters` | The onchain initialization parameters (see below). | #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-3-template-parameters-3) 3.3. Template parameters **Required Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `name` | String | The onchain contract name. Use `MyMultiToken`. | | `defaultAdmin` | String | The address with administrator permissions. Use your Dev-Controlled Wallet address. | | `primarySaleRecipient` | String | The address for first-time sale proceeds. Use your Dev-Controlled Wallet address. | | `royaltyRecipient` | String | The address for secondary sale royalties. Use your Dev-Controlled Wallet address. | | `royaltyPercent` | Float | The royalty share as a decimal (for example, `0.01` for 1%). Use `0.01`. | **Optional Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `symbol` | String | The token symbol (for example, `MMTK`). | | `platformFeeRecipient` | String | The address that receives platform fees from sales. Set this when implementing platform fee revenue share. | | `platformFeePercent` | Float | The platform fee percentage as decimal (for example, `0.1` for 10%). Requires `platformFeeRecipient`. | | `contractUri` | String | The URL for the contract metadata. | | `trustedForwarders` | Strings\[\] | A list of addresses that can forward ERC2771 meta-transactions to this contract. | ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-4-deploy-the-smart-contract-3) Step 4: Deploy the smart contract Deploy by making a request to [`POST /templates/{id}/deploy`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/deploy-contract-template) : deploy-erc1155.ts deploy\_erc1155.py cURL import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const response = await circleContractSdk.deployContractTemplate({ id: "aea21da6-0aa2-4971-9a1a-5098842b1248", blockchain: "ARC-TESTNET", name: "MyMultiTokenContract", walletId: process.env.WALLET_ID, templateParameters: { name: "MyMultiToken", symbol: "MMTK", defaultAdmin: process.env.WALLET_ADDRESS, primarySaleRecipient: process.env.WALLET_ADDRESS, royaltyRecipient: process.env.WALLET_ADDRESS, royaltyPercent: 0.01, }, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(response.data, null, 2)); **Run the script:** Node.js Python npm run deploy-erc1155 **Response:** { "contractIds": ["019c053d-1ed1-772b-91a8-6970003dad8d"], "transactionId": "5b6185b2-f9a1-5645-9db2-ca5d9a330794" } A successful response indicates deployment has been **initiated**, not completed. Use the `transactionId` to check the deployment status in the next step. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-1-check-deployment-status-3) 4.1. Check deployment status Verify deployment with [`GET /transactions/{id}`](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/get-transaction) .After running the deployment script, copy the `transactionId` from the response and update your `.env` file with `TRANSACTION_ID={your-transaction-id}`. Then run the check-transaction script to verify deployment status. check-transaction.ts check\_transaction.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const transactionResponse = await circleDeveloperSdk.getTransaction({ id: process.env.TRANSACTION_ID!, }); console.log(JSON.stringify(transactionResponse.data, null, 2)); **Run the script:** Node.js Python npm run check-transaction Transaction status may show PENDING immediately after deployment. Wait 10-30 seconds and re-run check-transaction to see COMPLETE status. **Response:** { "transaction": { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "blockchain": "ARC-TESTNET", "walletId": "45692c3e-2ffa-5c5b-a99c-61366939114c", "sourceAddress": "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758", "contractAddress": "0x281156899e5bd6fecf1c0831ee24894eeeaea2f8", "transactionType": "OUTBOUND", "custodyType": "DEVELOPER", "state": "COMPLETE", "amounts": [], "nfts": null, "txHash": "0x3bfbab5d5ce0d1a5d682cbc742d3940cf59db0369d173b71ba2a3b8f43bfbcb1", "blockHash": "0x7d12148f9331556b31f84f58a41b7ff16eaaa47940f9e86733037d7ab74d858e", "blockHeight": 23686153, "userOpHash": "0x66befac1a371fcdddf1566215e4677127e111dff9253f306f7096fed8642a208", "networkFee": "0.044628774800664", "firstConfirmDate": "2026-01-26T08:59:56Z", "operation": "CONTRACT_EXECUTION", "feeLevel": "MEDIUM", "estimatedFee": { "gasLimit": "500797", "networkFee": "0.16506442157883425", "baseFee": "160", "priorityFee": "9.60345525", "maxFee": "329.60345525" }, "refId": "", "abiFunctionSignature": "mintTo(address,uint256)", "abiParameters": [\ "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758",\ "1000000000000000000"\ ], "createDate": "2026-01-26T08:59:54Z", "updateDate": "2026-01-26T08:59:56Z" } } #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-2-get-the-contract-address-3) 4.2. Get the contract address After deployment completes, retrieve the contract address using [`GET /contracts/{id}`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/get-contract) .After deployment completes, copy the `contractIds[0]` from the deployment response and update your `.env` file with `CONTRACT_ID={your-contract-id}`. Then run the get-contract script to retrieve the contract address. get-contract.ts get\_contract.py import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const contractResponse = await circleContractSdk.getContract({ id: process.env.CONTRACT_ID!, }); console.log(JSON.stringify(contractResponse.data, null, 2)); **Run the script:** Node.js Python npm run get-contract **Response:** { "contract": { "id": "b7c35372-ce69-4ccd-bfaa-504c14634f0d", "contractAddress": "0x1234567890abcdef1234567890abcdef12345678", "blockchain": "ARC-TESTNET", "status": "COMPLETE" } } * * * [​](https://docs.arc.network/arc/tutorials/deploy-contracts#deploy-an-airdrop-contract) Deploy an airdrop contract --------------------------------------------------------------------------------------------------------------------- The Airdrop template enables mass token distribution to many recipients. Use this template for treasury distributions, stakeholder settlements, operational payments, or programmatic capital allocation. ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-3-prepare-for-deployment-4) Step 3: Prepare for deployment #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-1-get-your-wallet-information-4) 3.1. Get your wallet information Retrieve your wallet ID from Step 2. Ensure: * Wallet custody type is **Dev-Controlled** * Blockchain is **Arc Testnet** * Account type is **SCA** (Smart Contract Account, recommended for Gas Station compatibility) Note your wallet’s address for subsequent steps. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-2-understand-deployment-parameters-4) 3.2. Understand deployment parameters | Parameter | Description | | --- | --- | | `idempotencyKey` | A unique value to prevent duplicate requests. | | `name` | The offchain contract name (visible in Circle Console only). Use `MyAirdropContract`. | | `walletId` | The ID of the wallet deploying the contract. Use your dev-controlled wallet ID. | | `templateId` | The template identifier. Use `13e322f2-18dc-4f57-8eed-4bddfc50f85e` for Airdrop. See [Templates](https://developers.circle.com/contracts/scp-templates-overview)
. | | `blockchain` | The network to deploy onto. Use `ARC-TESTNET`. | | `entitySecretCiphertext` | The re-encrypted entity secret. See [Entity Secret Management](https://developers.circle.com/wallets/dev-controlled/entity-secret-management)
. | | `feeLevel` | The fee level for transaction processing. Use `MEDIUM`. | | `templateParameters` | The onchain initialization parameters (see below). | #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#3-3-template-parameters-4) 3.3. Template parameters **Required Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `defaultAdmin` | String | The address with administrator permissions. Use your Dev-Controlled Wallet address. | **Optional Parameters:** | Parameter | Type | Description | | --- | --- | --- | | `contractURI` | String | The URL for the contract metadata. | ### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#step-4-deploy-the-smart-contract-4) Step 4: Deploy the smart contract Deploy by making a request to [`POST /templates/{id}/deploy`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/deploy-contract-template) : deploy-airdrop.ts deploy\_airdrop.py cURL import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const response = await circleContractSdk.deployContractTemplate({ id: "13e322f2-18dc-4f57-8eed-4bddfc50f85e", blockchain: "ARC-TESTNET", name: "MyAirdropContract", walletId: process.env.WALLET_ID, templateParameters: { defaultAdmin: process.env.WALLET_ADDRESS, }, fee: { type: "level", config: { feeLevel: "MEDIUM", }, }, }); console.log(JSON.stringify(response.data, null, 2)); **Run the script:** Node.js Python npm run deploy-airdrop **Response:** { "contractIds": ["019c053d-1ed1-772b-91a8-6970003dad8d"], "transactionId": "5b6185b2-f9a1-5645-9db2-ca5d9a330794" } A successful response indicates deployment has been **initiated**, not completed. Use the `transactionId` to check the deployment status in the next step. #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-1-check-deployment-status-4) 4.1. Check deployment status Verify deployment with [`GET /transactions/{id}`](https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/get-transaction) .After running the deployment script, copy the `transactionId` from the response and update your `.env` file with `TRANSACTION_ID={your-transaction-id}`. Then run the check-transaction script to verify deployment status. check-transaction.ts check\_transaction.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const transactionResponse = await circleDeveloperSdk.getTransaction({ id: process.env.TRANSACTION_ID!, }); console.log(JSON.stringify(transactionResponse.data, null, 2)); **Run the script:** Node.js Python npm run check-transaction Transaction status may show PENDING immediately after deployment. Wait 10-30 seconds and re-run check-transaction to see COMPLETE status. **Response:** { "transaction": { "id": "601a0815-f749-41d8-b193-22cadd2a8977", "blockchain": "ARC-TESTNET", "walletId": "45692c3e-2ffa-5c5b-a99c-61366939114c", "sourceAddress": "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758", "contractAddress": "0x281156899e5bd6fecf1c0831ee24894eeeaea2f8", "transactionType": "OUTBOUND", "custodyType": "DEVELOPER", "state": "COMPLETE", "amounts": [], "nfts": null, "txHash": "0x3bfbab5d5ce0d1a5d682cbc742d3940cf59db0369d173b71ba2a3b8f43bfbcb1", "blockHash": "0x7d12148f9331556b31f84f58a41b7ff16eaaa47940f9e86733037d7ab74d858e", "blockHeight": 23686153, "userOpHash": "0x66befac1a371fcdddf1566215e4677127e111dff9253f306f7096fed8642a208", "networkFee": "0.044628774800664", "firstConfirmDate": "2026-01-26T08:59:56Z", "operation": "CONTRACT_EXECUTION", "feeLevel": "MEDIUM", "estimatedFee": { "gasLimit": "500797", "networkFee": "0.16506442157883425", "baseFee": "160", "priorityFee": "9.60345525", "maxFee": "329.60345525" }, "refId": "", "abiFunctionSignature": "mintTo(address,uint256)", "abiParameters": [\ "0xbcf83d3b112cbf43b19904e376dd8dee01fe2758",\ "1000000000000000000"\ ], "createDate": "2026-01-26T08:59:54Z", "updateDate": "2026-01-26T08:59:56Z" } } #### [​](https://docs.arc.network/arc/tutorials/deploy-contracts#4-2-get-the-contract-address-4) 4.2. Get the contract address After deployment completes, retrieve the contract address using [`GET /contracts/{id}`](https://developers.circle.com/api-reference/contracts/smart-contract-platform/get-contract) .After deployment completes, copy the `contractIds[0]` from the deployment response and update your `.env` file with `CONTRACT_ID={your-contract-id}`. Then run the get-contract script to retrieve the contract address. get-contract.ts get\_contract.py import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform"; const circleContractSdk = initiateSmartContractPlatformClient({ apiKey: process.env.CIRCLE_API_KEY, entitySecret: process.env.CIRCLE_ENTITY_SECRET, }); const contractResponse = await circleContractSdk.getContract({ id: process.env.CONTRACT_ID!, }); console.log(JSON.stringify(contractResponse.data, null, 2)); **Run the script:** Node.js Python npm run get-contract **Response:** { "contract": { "id": "b7c35372-ce69-4ccd-bfaa-504c14634f0d", "contractAddress": "0x1234567890abcdef1234567890abcdef12345678", "blockchain": "ARC-TESTNET", "status": "COMPLETE" } } * * * * * * [​](https://docs.arc.network/arc/tutorials/deploy-contracts#summary) Summary ------------------------------------------------------------------------------- After completing this tutorial, you’ve successfully: * Created a dev-controlled wallet on Arc Testnet * Funded your wallet with testnet USDC * Deployed a smart contract using Contract Templates * Retrieved your contract address Was this page helpful? YesNo [llms.txt](https://docs.arc.network/ai/llms) [Bridge USDC to Arc](https://docs.arc.network/arc/tutorials/bridge-usdc-to-arc) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Create your first ERC-8183 job - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Agentic economy Create your first ERC-8183 job [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [ERC-8183 contract on Arc testnet](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#erc-8183-contract-on-arc-testnet) * [Verify the result](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#verify-the-result) * [Summary](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#summary) This quickstart guides you through the ERC-8183 job lifecycle on Arc Testnet. You’ll create developer-controlled smart contract account wallets, create a job, fund escrow with USDC, submit a deliverable hash, and complete the job as the evaluator. Select the tab that matches your preferred setup. [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#erc-8183-contract-on-arc-testnet) ERC-8183 contract on Arc testnet ----------------------------------------------------------------------------------------------------------------------------------------------- | Contract | Address | | --- | --- | | AgenticCommerce reference implementation | [`0x0747EEf0706327138c69792bF28Cd525089e4583`](https://testnet.arcscan.app/address/0x0747EEf0706327138c69792bF28Cd525089e4583) | * Circle Wallets * Viem [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#prerequisites) Prerequisites --------------------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. A [Circle Developer Console](https://console.circle.com/) account 2. An API key created in the Console: **Keys → Create a key → API key → Standard Key** 3. Your [Entity Secret registered](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-1-set-up-your-project) Step 1. Set up your project ------------------------------------------------------------------------------------------------------------------------------------ Create a project directory, install dependencies, and configure your environment. ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#1-1-create-the-project-and-install-dependencies) 1.1. Create the project and install dependencies Node.js Python mkdir erc8183-quickstart cd erc8183-quickstart npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" npm install @circle-fin/developer-controlled-wallets viem npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#1-3-set-environment-variables) 1.3. Set environment variables Create a `.env` file in the project directory and add your Circle credentials: CIRCLE_API_KEY=YOUR_API_KEY CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET * `CIRCLE_API_KEY` is your Circle Developer API key. * `CIRCLE_ENTITY_SECRET` is your registered Entity Secret. The `npm run start` command loads variables from `.env` using Node.js native env-file support. The `python index.py` command loads the same `.env` file via `python-dotenv`. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-2-create-developer-controlled-wallets) Step 2. Create developer-controlled wallets -------------------------------------------------------------------------------------------------------------------------------------------------------------------- In this step, you create two Arc Testnet dev-controlled wallets for the ERC-8183 flow: a client wallet and a provider wallet. In this quickstart, the client also acts as the evaluator. If you already have two Arc Testnet funded dev-controlled wallets for this flow, skip to [Step 4](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-4-create-the-job) .The Step 2 through 9 sections explain the flow in smaller pieces. Not every step includes a code snippet, and the snippets are not cumulative. To run the full workflow end to end, use the [complete script](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#full-job-lifecycle-script) at the end of this tutorial. index.ts index.py const walletSet = await circleClient.createWalletSet({ name: "ERC8183 Job Wallets", }); const walletsResponse = await circleClient.createWallets({ blockchains: ["ARC-TESTNET"], count: 2, walletSetId: walletSet.data?.walletSet?.id ?? "", accountType: "SCA", }); const clientWallet = walletsResponse.data?.wallets?.[0]!; const providerWallet = walletsResponse.data?.wallets?.[1]!; console.log(`Client: ${clientWallet.address} (${clientWallet.id})`); console.log(`Provider: ${providerWallet.address} (${providerWallet.id})`); console.log(`Evaluator: ${clientWallet.address} (${clientWallet.id})`); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-3-fund-the-client-wallet) Step 3. Fund the client wallet ------------------------------------------------------------------------------------------------------------------------------------------ The script will pause to allow you to fund the client wallet with Arc Testnet USDC from one of these faucets: * [Circle Faucet](https://faucet.circle.com/) * [Circle Console Faucet](https://console.circle.com/faucet) You only fund the client wallet as the script transfers starter USDC to the provider wallet automatically before the ERC-8183 flow begins. The public faucet is rate-limited, so this quickstart avoids requiring a second faucet request for the provider wallet. [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-4-create-the-job) Step 4. Create the job -------------------------------------------------------------------------------------------------------------------------- Call `createJob(provider, evaluator, expiredAt, description, hook)` on the deployed ERC-8183 reference implementation. This creates the job in the `Open` state. This quickstart uses `address(0)` for `hook` so the flow stays on the default non-hooked path. index.ts index.py const createJobTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "createJob(address,address,uint256,string,address)", abiParameters: [\ providerWallet.address!,\ clientWallet.address!,\ expiredAt.toString(),\ "ERC-8183 demo job on Arc Testnet",\ "0x0000000000000000000000000000000000000000",\ ], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-5-set-the-budget) Step 5. Set the budget -------------------------------------------------------------------------------------------------------------------------- In this deployed contract, the provider sets the job price by calling `setBudget(jobId, amount, optParams)`. index.ts index.py const setBudgetTx = await circleClient.createContractExecutionTransaction({ walletAddress: providerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "setBudget(uint256,uint256,bytes)", abiParameters: [jobId.toString(), JOB_BUDGET.toString(), "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-6-approve-usdc-and-fund-escrow) Step 6. Approve USDC and fund escrow ------------------------------------------------------------------------------------------------------------------------------------------------------ Before the client can fund the job, the USDC contract must approve the ERC-8183 contract to transfer the escrow amount. Then the client calls `fund(jobId, optParams)` to move the job into the `Funded` state. index.ts index.py const approveTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: "0x3600000000000000000000000000000000000000", abiFunctionSignature: "approve(address,uint256)", abiParameters: [AGENTIC_COMMERCE_CONTRACT, JOB_BUDGET.toString()], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); const fundTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "fund(uint256,bytes)", abiParameters: [jobId.toString(), "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-7-submit-the-deliverable) Step 7. Submit the deliverable ------------------------------------------------------------------------------------------------------------------------------------------ The provider submits a `bytes32` deliverable hash, moving the job into the `Submitted` state. index.ts index.py const deliverableHash = keccak256(toHex("arc-erc8183-demo-deliverable")); const submitTx = await circleClient.createContractExecutionTransaction({ walletAddress: providerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "submit(uint256,bytes32,bytes)", abiParameters: [jobId.toString(), deliverableHash, "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-8-complete-the-job) Step 8. Complete the job ------------------------------------------------------------------------------------------------------------------------------ The evaluator completes the job by calling `complete(jobId, reason, optParams)`. In this quickstart, the client is also the evaluator. index.ts index.py const reasonHash = keccak256(toHex("deliverable-approved")); const completeTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "complete(uint256,bytes32,bytes)", abiParameters: [jobId.toString(), reasonHash, "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-9-check-the-final-job-state) Step 9. Check the final job state ------------------------------------------------------------------------------------------------------------------------------------------------ Read the job back from the contract to confirm it reached `Completed`. This reference implementation does not return the deliverable in `getJob()`, so the script prints the submitted deliverable hash from local flow state instead. index.ts index.py const job = await publicClient.readContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "getJob", args: [jobId], }); console.log(`Job ID: ${jobId}`); console.log(`Status: ${STATUS_NAMES[Number(job.status)]}`); console.log(`Budget: ${formatUnits(job.budget, 6)} USDC`); console.log(`Hook: ${job.hook}`); console.log(`Deliverable hash submitted: ${deliverableHash}`); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#full-job-lifecycle-script) Full job lifecycle script --------------------------------------------------------------------------------------------------------------------------------- These complete scripts below combines all the preceding steps into a single runnable file. index.ts index.py import { createInterface } from "node:readline/promises"; import { setTimeout as delay } from "node:timers/promises"; import { stdin as input, stdout as output } from "node:process"; import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; import { createPublicClient, decodeEventLog, formatUnits, http, keccak256, parseUnits, toHex, type Address, type Hex, } from "viem"; import { arcTestnet } from "viem/chains"; // To bootstrap provider wallet during setup (see Step 3) const PROVIDER_STARTER_BALANCE = "1"; const AGENTIC_COMMERCE_CONTRACT = "0x0747EEf0706327138c69792bF28Cd525089e4583" as Address; const JOB_BUDGET = parseUnits("5", 6); // 5 USDC (ERC-20, 6 decimals) const circleClient = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY!, entitySecret: process.env.CIRCLE_ENTITY_SECRET!, }); const publicClient = createPublicClient({ chain: arcTestnet, transport: http(), }); const agenticCommerceAbi = [\ {\ type: "function",\ name: "createJob",\ stateMutability: "nonpayable",\ inputs: [\ { name: "provider", type: "address" },\ { name: "evaluator", type: "address" },\ { name: "expiredAt", type: "uint256" },\ { name: "description", type: "string" },\ { name: "hook", type: "address" },\ ],\ outputs: [{ name: "jobId", type: "uint256" }],\ },\ {\ type: "function",\ name: "setBudget",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "amount", type: "uint256" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ type: "function",\ name: "fund",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ type: "function",\ name: "submit",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "deliverable", type: "bytes32" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ type: "function",\ name: "complete",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "reason", type: "bytes32" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ type: "function",\ name: "getJob",\ stateMutability: "view",\ inputs: [{ name: "jobId", type: "uint256" }],\ outputs: [\ {\ type: "tuple",\ components: [\ { name: "id", type: "uint256" },\ { name: "client", type: "address" },\ { name: "provider", type: "address" },\ { name: "evaluator", type: "address" },\ { name: "description", type: "string" },\ { name: "budget", type: "uint256" },\ { name: "expiredAt", type: "uint256" },\ { name: "status", type: "uint8" },\ { name: "hook", type: "address" },\ ],\ },\ ],\ },\ {\ type: "event",\ name: "JobCreated",\ inputs: [\ { indexed: true, name: "jobId", type: "uint256" },\ { indexed: true, name: "client", type: "address" },\ { indexed: true, name: "provider", type: "address" },\ { indexed: false, name: "evaluator", type: "address" },\ { indexed: false, name: "expiredAt", type: "uint256" },\ { indexed: false, name: "hook", type: "address" },\ ],\ anonymous: false,\ },\ ] as const; const STATUS_NAMES = [\ "Open",\ "Funded",\ "Submitted",\ "Completed",\ "Rejected",\ "Expired",\ ]; function extractJobId(txHash: Hex) { return publicClient .getTransactionReceipt({ hash: txHash }) .then((receipt) => { for (const log of receipt.logs) { try { const decoded = decodeEventLog({ abi: agenticCommerceAbi, data: log.data, topics: log.topics, }); if (decoded.eventName === "JobCreated") { return decoded.args.jobId; } } catch { continue; } } throw new Error("Could not parse JobCreated event"); }); } async function waitForTransaction(txId: string, label: string) { process.stdout.write(` Waiting for ${label}`); for (let i = 0; i < 60; i++) { await delay(2000); const tx = await circleClient.getTransaction({ id: txId }); const data = tx.data?.transaction; if (data?.state === "COMPLETE" && data.txHash) { const txHash = data.txHash; console.log( ` ✓\n Tx: ${arcTestnet.blockExplorers.default.url}/tx/${txHash}`, ); return txHash as Hex; } if (data?.state === "FAILED") { throw new Error(`${label} failed onchain`); } process.stdout.write("."); } throw new Error(`${label} timed out`); } async function printBalances( title: string, wallets: Array<{ label: string; id?: string; address?: string | null }>, ) { console.log(`\n${title}:`); for (const wallet of wallets) { const balances = await circleClient.getWalletTokenBalance({ id: wallet.id!, }); const usdc = balances.data?.tokenBalances?.find( (b) => b.token?.symbol === "USDC", ); console.log(` ${wallet.label}: ${wallet.address}`); console.log(` USDC: ${usdc?.amount ?? "0"}`); } } async function main() { console.log("── Step 1: Create wallets ──"); const walletSet = await circleClient.createWalletSet({ name: "ERC8183 Job Wallets", }); const walletsResponse = await circleClient.createWallets({ blockchains: ["ARC-TESTNET"], count: 2, walletSetId: walletSet.data?.walletSet?.id ?? "", accountType: "SCA", }); const clientWallet = walletsResponse.data?.wallets?.[0]!; const providerWallet = walletsResponse.data?.wallets?.[1]!; console.log("\n── Step 2: Fund the client wallet ──"); console.log(" Fund this wallet with Arc Testnet USDC:"); console.log(` Client: ${clientWallet.address}`); console.log(` Wallet ID: ${clientWallet.id}`); console.log(" Public faucet: https://faucet.circle.com"); console.log(" Console faucet: https://console.circle.com/faucet"); console.log("\n This script will fund the provider wallet automatically."); const rl = createInterface({ input, output }); await rl.question("\nPress Enter after the client wallet is funded... "); rl.close(); console.log("\n── Step 3: Transfer starter USDC to provider ──"); const transferTx = await circleClient.createTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", tokenAddress: "0x3600000000000000000000000000000000000000", destinationAddress: providerWallet.address!, amount: [PROVIDER_STARTER_BALANCE], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction( transferTx.data?.id!, "transfer starter USDC to provider", ); console.log("\n── Step 4: Check balances ──"); await printBalances("Balances", [\ { label: "Client", ...clientWallet },\ { label: "Provider", ...providerWallet },\ ]); const now = await publicClient.getBlock(); const expiredAt = now.timestamp + 3600n; console.log("\n── Step 5: Create job - createJob() ──"); const createJobTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "createJob(address,address,uint256,string,address)", abiParameters: [\ providerWallet.address!,\ clientWallet.address!,\ expiredAt.toString(),\ "ERC-8183 demo job on Arc Testnet",\ "0x0000000000000000000000000000000000000000",\ ], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); const createJobTxHash = await waitForTransaction( createJobTx.data?.id!, "create job", ); const jobId = await extractJobId(createJobTxHash); console.log(` Job ID: ${jobId}`); console.log("\n── Step 6: Set budget - setBudget() ──"); const setBudgetTx = await circleClient.createContractExecutionTransaction({ walletAddress: providerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "setBudget(uint256,uint256,bytes)", abiParameters: [jobId.toString(), JOB_BUDGET.toString(), "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction(setBudgetTx.data?.id!, "set budget"); console.log("\n── Step 7: Approve USDC - approve() ──"); const approveTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: "0x3600000000000000000000000000000000000000", abiFunctionSignature: "approve(address,uint256)", abiParameters: [AGENTIC_COMMERCE_CONTRACT, JOB_BUDGET.toString()], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction(approveTx.data?.id!, "approve USDC"); console.log("\n── Step 8: Fund escrow - fund() ──"); const fundTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "fund(uint256,bytes)", abiParameters: [jobId.toString(), "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction(fundTx.data?.id!, "fund escrow"); console.log("\n── Step 9: Submit deliverable - submit() ──"); const deliverableHash = keccak256(toHex("arc-erc8183-demo-deliverable")); const submitTx = await circleClient.createContractExecutionTransaction({ walletAddress: providerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "submit(uint256,bytes32,bytes)", abiParameters: [jobId.toString(), deliverableHash, "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction(submitTx.data?.id!, "submit deliverable"); console.log("\n── Step 10: Complete job - complete() ──"); const reasonHash = keccak256(toHex("deliverable-approved")); const completeTx = await circleClient.createContractExecutionTransaction({ walletAddress: clientWallet.address!, blockchain: "ARC-TESTNET", contractAddress: AGENTIC_COMMERCE_CONTRACT, abiFunctionSignature: "complete(uint256,bytes32,bytes)", abiParameters: [jobId.toString(), reasonHash, "0x"], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction(completeTx.data?.id!, "complete job"); console.log("\n── Step 11: Check final job state ──"); const job = await publicClient.readContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "getJob", args: [jobId], }); console.log(` Job ID: ${jobId}`); console.log(` Status: ${STATUS_NAMES[Number(job.status)]}`); console.log(` Budget: ${formatUnits(job.budget, 6)} USDC`); console.log(` Hook: ${job.hook}`); console.log(` Deliverable hash submitted: ${deliverableHash}`); console.log("\n── Step 12: Check final balances ──"); await printBalances("Balances", [\ { label: "Client", ...clientWallet },\ { label: "Provider", ...providerWallet },\ ]); } main().catch((error) => { console.error("\nError:", error.message || error); process.exit(1); }); See all 354 lines Run the script: Node.js Python npm run start [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#prerequisites-2) Prerequisites ----------------------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. Installed [Node.js v22+](https://nodejs.org/) 2. Two self-managed EVM wallets for Arc Testnet * Testnet USDC in both wallets to pay for gas and for the client wallet to fund escrow [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-1-set-up-your-project-2) Step 1. Set up your project -------------------------------------------------------------------------------------------------------------------------------------- Create a project directory, install dependencies, and configure your environment. ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#1-1-create-the-project-and-install-dependencies-2) 1.1. Create the project and install dependencies mkdir erc8183-quickstart cd erc8183-quickstart npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" npm install viem npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#1-2-configure-typescript-optional-2) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#1-3-set-environment-variables-2) 1.3. Set environment variables Create a `.env` file in the project directory and add the two private keys used for the flow: CLIENT_PRIVATE_KEY=0xYOUR_CLIENT_PRIVATE_KEY PROVIDER_PRIVATE_KEY=0xYOUR_PROVIDER_PRIVATE_KEY * `CLIENT_PRIVATE_KEY` is the `0x`\-prefixed private key for the Arc Testnet wallet that creates the job, approves USDC, funds escrow, and completes the job as the evaluator. * `PROVIDER_PRIVATE_KEY` is the `0x`\-prefixed private key for the Arc Testnet wallet that sets the budget and submits the deliverable. The `npm run start` command loads variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-2-prepare-your-wallets) Step 2. Prepare your wallets -------------------------------------------------------------------------------------------------------------------------------------- In this step, you prepare two self-managed Arc Testnet wallets for the ERC-8183 flow. One wallet acts as the client and evaluator, and the other acts as the provider. If you already have two funded Arc Testnet wallets for this flow, skip to [Step 3](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-3-create-the-job) .The Step 3 through 8 code snippets explain the flow in smaller pieces. They are not cumulative and will not run if pasted together. To run the full workflow end to end, use the [complete script](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#full-job-lifecycle-script-2) at the end of this tab. ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#2-1-create-or-fund-your-wallets) 2.1. Create or fund your wallets Create two self-managed EVM wallets if you do not already have them. For example, you can generate throwaway wallets with Foundry: cast wallet new --json Run it twice, once for the client wallet and once for the provider wallet, then fund both wallets with Arc Testnet USDC so they can submit transactions. Fund the client wallet with Arc Testnet USDC so it can escrow the job budget. ### [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#2-2-confirm-wallet-roles) 2.2. Confirm wallet roles * the client wallet creates the job, approves USDC, funds escrow, and completes the job as the evaluator * the provider wallet sets the budget and submits the deliverable [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-3-create-the-job) Step 3. Create the job -------------------------------------------------------------------------------------------------------------------------- Call `createJob(provider, evaluator, expiredAt, description, hook)` on the deployed ERC-8183 reference implementation. This creates the job in the `Open` state. This quickstart uses `address(0)` for `hook` so the flow stays on the default non-hooked path. index.ts const block = await publicClient.getBlock(); const expiredAt = block.timestamp + 3600n; const createJobHash = await clientWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "createJob", args: [\ providerAccount.address,\ clientAccount.address,\ expiredAt,\ "ERC-8183 demo job on Arc Testnet",\ "0x0000000000000000000000000000000000000000",\ ], }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-4-set-the-budget) Step 4. Set the budget -------------------------------------------------------------------------------------------------------------------------- In this deployed contract, the provider sets the job price by calling `setBudget(jobId, amount, optParams)`. index.ts const setBudgetHash = await providerWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "setBudget", args: [jobId, JOB_BUDGET, "0x"], }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-5-approve-usdc-and-fund-escrow) Step 5. Approve USDC and fund escrow ------------------------------------------------------------------------------------------------------------------------------------------------------ Before the client can fund the job, the USDC contract must approve the ERC-8183 contract to transfer the escrow amount. Then the client calls `fund(jobId, optParams)` to move the job into the `Funded` state. index.ts const approveHash = await clientWalletClient.writeContract({ address: USDC_CONTRACT, abi: erc20Abi, functionName: "approve", args: [AGENTIC_COMMERCE_CONTRACT, JOB_BUDGET], }); const fundHash = await clientWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "fund", args: [jobId, "0x"], }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-6-submit-the-deliverable) Step 6. Submit the deliverable ------------------------------------------------------------------------------------------------------------------------------------------ The provider submits a `bytes32` deliverable hash, moving the job into the `Submitted` state. index.ts const deliverableHash = keccak256(toHex("arc-erc8183-demo-deliverable")); const submitHash = await providerWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "submit", args: [jobId, deliverableHash, "0x"], }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-7-complete-the-job) Step 7. Complete the job ------------------------------------------------------------------------------------------------------------------------------ The evaluator completes the job by calling `complete(jobId, reason, optParams)`. In this quickstart, the client is also the evaluator. index.ts const reasonHash = keccak256(toHex("work-delivered-and-approved")); const completeHash = await clientWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "complete", args: [jobId, reasonHash, "0x"], }); [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#step-8-check-the-final-job-state) Step 8. Check the final job state ------------------------------------------------------------------------------------------------------------------------------------------------ Read the job back from the contract to confirm it reached `Completed`. This reference implementation does not return the deliverable in `getJob()`, so the script prints the submitted deliverable hash from local flow state instead. index.ts const job = await publicClient.readContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "getJob", args: [jobId], }); console.log(`Job ID: ${job.id}`); console.log(`Status: ${STATUS_NAMES[Number(job.status)]}`); console.log(`Budget: ${formatUnits(job.budget, 6)} USDC`); console.log(`Hook: ${job.hook}`); console.log(`Deliverable hash submitted: ${deliverableHash}`); This complete script combines the preceding steps into a single runnable file. [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#full-job-lifecycle-script-2) Full job lifecycle script ----------------------------------------------------------------------------------------------------------------------------------- index.ts import { createPublicClient, createWalletClient, decodeEventLog, formatUnits, http, keccak256, toHex, } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { arcTestnet } from "viem/chains"; const AGENTIC_COMMERCE_CONTRACT = "0x0747EEf0706327138c69792bF28Cd525089e4583"; const USDC_CONTRACT = "0x3600000000000000000000000000000000000000"; const JOB_BUDGET = 1_000_000n; const clientAccount = privateKeyToAccount( process.env.CLIENT_PRIVATE_KEY as `0x${string}`, ); const providerAccount = privateKeyToAccount( process.env.PROVIDER_PRIVATE_KEY as `0x${string}`, ); const publicClient = createPublicClient({ chain: arcTestnet, transport: http(), }); const clientWalletClient = createWalletClient({ account: clientAccount, chain: arcTestnet, transport: http(), }); const providerWalletClient = createWalletClient({ account: providerAccount, chain: arcTestnet, transport: http(), }); const agenticCommerceAbi = [\ {\ name: "createJob",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "provider", type: "address" },\ { name: "evaluator", type: "address" },\ { name: "expiredAt", type: "uint256" },\ { name: "description", type: "string" },\ { name: "hook", type: "address" },\ ],\ outputs: [{ name: "jobId", type: "uint256" }],\ },\ {\ name: "setBudget",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "amount", type: "uint256" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ name: "fund",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ name: "submit",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "deliverable", type: "bytes32" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ name: "complete",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "jobId", type: "uint256" },\ { name: "reason", type: "bytes32" },\ { name: "optParams", type: "bytes" },\ ],\ outputs: [],\ },\ {\ name: "getJob",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "jobId", type: "uint256" }],\ outputs: [\ {\ type: "tuple",\ components: [\ { name: "id", type: "uint256" },\ { name: "client", type: "address" },\ { name: "provider", type: "address" },\ { name: "evaluator", type: "address" },\ { name: "description", type: "string" },\ { name: "budget", type: "uint256" },\ { name: "expiredAt", type: "uint256" },\ { name: "status", type: "uint8" },\ { name: "hook", type: "address" },\ ],\ },\ ],\ },\ {\ name: "JobCreated",\ type: "event",\ anonymous: false,\ inputs: [\ { indexed: true, name: "jobId", type: "uint256" },\ { indexed: true, name: "client", type: "address" },\ { indexed: true, name: "provider", type: "address" },\ { indexed: false, name: "evaluator", type: "address" },\ { indexed: false, name: "expiredAt", type: "uint256" },\ { indexed: false, name: "hook", type: "address" },\ ],\ },\ ] as const; const erc20Abi = [\ {\ name: "approve",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "spender", type: "address" },\ { name: "amount", type: "uint256" },\ ],\ outputs: [{ name: "", type: "bool" }],\ },\ {\ name: "balanceOf",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "account", type: "address" }],\ outputs: [{ name: "", type: "uint256" }],\ },\ ] as const; const STATUS_NAMES = [\ "Open",\ "Funded",\ "Submitted",\ "Completed",\ "Rejected",\ "Expired",\ ]; async function waitForTransaction(hash: `0x${string}`, label: string) { process.stdout.write(` Waiting for ${label}`); const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log(` ✓\n Tx: ${arcTestnet.blockExplorers.default.url}/tx/${hash}`); return receipt; } async function printBalances(title: string) { console.log(`\n${title}:`); const clientBalance = await publicClient.readContract({ address: USDC_CONTRACT, abi: erc20Abi, functionName: "balanceOf", args: [clientAccount.address], }); const providerBalance = await publicClient.readContract({ address: USDC_CONTRACT, abi: erc20Abi, functionName: "balanceOf", args: [providerAccount.address], }); console.log(` Client: ${clientAccount.address}`); console.log(` USDC: ${formatUnits(clientBalance, 6)}`); console.log(` Provider: ${providerAccount.address}`); console.log(` USDC: ${formatUnits(providerBalance, 6)}`); } async function main(): Promise { console.log("── Step 1: Prepare accounts ──"); console.log(` Client: ${clientAccount.address}`); console.log(` Provider: ${providerAccount.address}`); console.log(` Evaluator: ${clientAccount.address}`); console.log("\n── Step 2: Check balances ──"); await printBalances("Balances"); const block = await publicClient.getBlock(); const expiredAt = block.timestamp + 3600n; console.log("\n── Step 3: Create job - createJob() ──"); const createJobHash = await clientWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "createJob", args: [\ providerAccount.address,\ clientAccount.address,\ expiredAt,\ "ERC-8183 demo job on Arc Testnet",\ "0x0000000000000000000000000000000000000000",\ ], }); const createJobReceipt = await waitForTransaction( createJobHash, "create job", ); let jobId: bigint | undefined; for (const log of createJobReceipt.logs) { try { const decoded = decodeEventLog({ abi: agenticCommerceAbi, data: log.data, topics: log.topics, }); if (decoded.eventName === "JobCreated") { jobId = decoded.args.jobId; break; } } catch { continue; } } if (jobId == null) { throw new Error("Could not parse JobCreated event"); } console.log(` Job ID: ${jobId}`); console.log("\n── Step 4: Set budget - setBudget() ──"); const setBudgetHash = await providerWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "setBudget", args: [jobId, JOB_BUDGET, "0x"], }); await waitForTransaction(setBudgetHash, "set budget"); console.log("\n── Step 5: Approve USDC - approve() ──"); const approveHash = await clientWalletClient.writeContract({ address: USDC_CONTRACT, abi: erc20Abi, functionName: "approve", args: [AGENTIC_COMMERCE_CONTRACT, JOB_BUDGET], }); await waitForTransaction(approveHash, "approve USDC"); console.log("\n── Step 6: Fund escrow - fund() ──"); const fundHash = await clientWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "fund", args: [jobId, "0x"], }); await waitForTransaction(fundHash, "fund escrow"); console.log("\n── Step 7: Submit deliverable - submit() ──"); const deliverableHash = keccak256(toHex("arc-erc8183-demo-deliverable")); const submitHash = await providerWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "submit", args: [jobId, deliverableHash, "0x"], }); await waitForTransaction(submitHash, "submit deliverable"); console.log("\n── Step 8: Complete job - complete() ──"); const reasonHash = keccak256(toHex("work-delivered-and-approved")); const completeHash = await clientWalletClient.writeContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "complete", args: [jobId, reasonHash, "0x"], }); await waitForTransaction(completeHash, "complete job"); console.log("\n── Step 9: Check final job state ──"); const job = await publicClient.readContract({ address: AGENTIC_COMMERCE_CONTRACT, abi: agenticCommerceAbi, functionName: "getJob", args: [jobId], }); console.log(` Job ID: ${job.id}`); console.log(` Status: ${STATUS_NAMES[Number(job.status)]}`); console.log(` Budget: ${formatUnits(job.budget, 6)} USDC`); console.log(` Hook: ${job.hook}`); console.log(` Deliverable hash submitted: ${deliverableHash}`); console.log("\n── Step 10: Check final balances ──"); await printBalances("Balances"); } void main().catch((error) => { console.error("\nError:", error); process.exit(1); }); See all 314 lines Run the script: npm run start [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#verify-the-result) Verify the result ----------------------------------------------------------------------------------------------------------------- If the flow succeeds, the output should show: * a created job ID * a completed final status * the client balance reduced by the funded escrow amount * the provider balance increased after completion If platform or evaluator fees are configured on the deployed contract, the provider receives the net amount after fees rather than the full job budget. You can also inspect the transaction links in the terminal output on [Arcscan Testnet](https://testnet.arcscan.app/) . [​](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job#summary) Summary --------------------------------------------------------------------------------------------- After completing this quickstart, you’ve successfully: * Set up a project for running an ERC-8183 job flow on Arc Testnet * Prepared client and provider wallets for the client, provider, and evaluator roles * Walked through an example ERC-8183 job lifecycle * Confirmed balances and job state in the script output and reviewed transactions on Arcscan Testnet Was this page helpful? YesNo [Register your first AI agent](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent) [App Kit overview](https://docs.arc.network/app-kit) ⌘I Assistant Responses are generated using AI and may contain mistakes. --- # Register your first AI agent - Arc Docs [Skip to main content](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#content-area) [Arc Docs home page![light logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_FC.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=8cd299fa4dc87ec5fb961a1269542a77)![dark logo](https://mintcdn.com/arc-docs/KcWqCvufSBkXI0Ew/logo/ARC_Doc_WHT.svg?fit=max&auto=format&n=KcWqCvufSBkXI0Ew&q=85&s=3c3f74b8c760a0750d28265293e8912d)](https://docs.arc.network/) Search... ⌘KAsk AI Search... Navigation Agentic economy Register your first AI agent [Home](https://docs.arc.network/) [Arc Network](https://docs.arc.network/arc-chain) [Build](https://docs.arc.network/build) [Integrate](https://docs.arc.network/integrate) On this page * [ERC-8004 contracts on Arc testnet](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#erc-8004-contracts-on-arc-testnet) * [Summary](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#summary) This quickstart guides you through registering an AI agent using the [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004) standard on Arc Testnet. You’ll create developer-controlled wallets, register your agent’s identity, record reputation events, and verify credentials. Select the tab that matches your preferred setup. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#erc-8004-contracts-on-arc-testnet) ERC-8004 contracts on Arc testnet ----------------------------------------------------------------------------------------------------------------------------------------------- | Contract | Address | | --- | --- | | IdentityRegistry | [`0x8004A818BFB912233c491871b3d84c89A494BD9e`](https://testnet.arcscan.app/address/0x8004A818BFB912233c491871b3d84c89A494BD9e) | | ReputationRegistry | [`0x8004B663056A597Dffe9eCcC1965A193B7388713`](https://testnet.arcscan.app/address/0x8004B663056A597Dffe9eCcC1965A193B7388713) | | ValidationRegistry | [`0x8004Cb1BF31DAf7788923b405b754f57acEB4272`](https://testnet.arcscan.app/address/0x8004Cb1BF31DAf7788923b405b754f57acEB4272) | * Circle Wallets * Viem [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. A [Circle Developer Console](https://console.circle.com/) account 2. An API key created in the Console: **Keys → Create a key → API key → Standard Key** 3. Your [Entity Secret registered](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-1-set-up-your-project) Step 1. Set up your project ---------------------------------------------------------------------------------------------------------------------------------- Create a project directory, install dependencies, and configure your environment. ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#1-1-create-the-project-and-install-dependencies) 1.1. Create the project and install dependencies Node.js Python mkdir erc8004-quickstart cd erc8004-quickstart npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" npm install @circle-fin/developer-controlled-wallets viem npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#1-2-configure-typescript-optional) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#1-3-set-environment-variables) 1.3. Set environment variables Create a `.env` file in the project directory and add your Circle credentials: CIRCLE_API_KEY=YOUR_API_KEY CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET Where `YOUR_API_KEY` is your Circle Developer API key and `YOUR_ENTITY_SECRET` is your registered Entity Secret.The `npm run start` command loads these variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-2-create-developer-controlled-wallets) Step 2. Create developer-controlled wallets ------------------------------------------------------------------------------------------------------------------------------------------------------------------ In this step, you create two Arc Testnet dev-controlled wallets for the ERC-8004 flow. One wallet owns the agent and the other records reputation. If you already have two Arc Testnet dev-controlled wallets for this flow, skip to [Step 3](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-3-prepare-agent-metadata) . Per ERC-8004, agent owners cannot record reputation for their own agents to prevent self-dealing.The Step 2 through 7 code snippets explain the flow in smaller pieces. They are not cumulative and will not run if pasted together. To run the full workflow end to end, use the [complete script](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#full-agent-registration-script) at the end of this tutorial. index.ts index.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; const circleClient = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY!, entitySecret: process.env.CIRCLE_ENTITY_SECRET!, }); const walletSet = await circleClient.createWalletSet({ name: "ERC8004 Agent Wallets", }); const walletsResponse = await circleClient.createWallets({ blockchains: ["ARC-TESTNET"], count: 2, walletSetId: walletSet.data?.walletSet?.id ?? "", accountType: "SCA", }); const ownerWallet = walletsResponse.data?.wallets?.[0]!; const validatorWallet = walletsResponse.data?.wallets?.[1]!; console.log(`Owner: ${ownerWallet.address}`); console.log(`Validator: ${validatorWallet.address}`); [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-3-prepare-agent-metadata) Step 3. Prepare agent metadata ---------------------------------------------------------------------------------------------------------------------------------------- Create a JSON file with metadata for your agent. The structure below is an example you can adapt for your use case. ERC-8004 registration stores a metadata URI, but the JSON fields at that URI are application-defined unless your integration follows a separate metadata convention. agent-metadata.json { "name": "DeFi Arbitrage Agent v1.0", "description": "Autonomous trading agent for cross-DEX arbitrage on Arc", "image": "ipfs://QmAgentAvatarHash...", "agent_type": "trading", "capabilities": [\ "arbitrage_detection",\ "liquidity_monitoring",\ "automated_execution"\ ], "version": "1.0.0" } Upload to IPFS using [Pinata](https://pinata.cloud/) , [NFT.Storage](https://nft.storage/) , [Web3.Storage](https://web3.storage/) or your preferred IPFS tool. You’ll receive an IPFS URI like `ipfs://QmYourHash...`. For this quickstart, you can skip uploading and use the example URI: `ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei` [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-4-register-your-agent-identity) Step 4. Register your agent identity ---------------------------------------------------------------------------------------------------------------------------------------------------- Call `register(metadataURI)` on the IdentityRegistry to mint an identity NFT for your agent. index.ts index.py const IDENTITY_REGISTRY = "0x8004A818BFB912233c491871b3d84c89A494BD9e"; const METADATA_URI = process.env.METADATA_URI || "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei"; const registerTx = await circleClient.createContractExecutionTransaction({ walletAddress: ownerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: IDENTITY_REGISTRY, abiFunctionSignature: "register(string)", abiParameters: [METADATA_URI], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); // Poll until confirmed let txHash: string | undefined; for (let i = 0; i < 30; i++) { await new Promise((r) => setTimeout(r, 2000)); const { data } = await circleClient.getTransaction({ id: registerTx.data?.id!, }); if (data?.transaction?.state === "COMPLETE") { txHash = data.transaction.txHash; break; } if (data?.transaction?.state === "FAILED") throw new Error("Registration failed"); } console.log(`Registered: https://testnet.arcscan.app/tx/${txHash}`); With Circle Gas Station, your application sponsors the transaction fees. On Arc, gas is approximately 0.006 USDC-TESTNET per transaction. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-5-retrieve-your-agent-id) Step 5. Retrieve your agent ID ---------------------------------------------------------------------------------------------------------------------------------------- Query the `Transfer` event from the IdentityRegistry to find the token ID minted for your agent. index.ts index.py import { createPublicClient, http, parseAbiItem, getContract } from "viem"; import { arcTestnet } from "viem/chains"; const publicClient = createPublicClient({ chain: arcTestnet, transport: http(), }); const latestBlock = await publicClient.getBlockNumber(); const blockRange = 10000n; // RPC limit: eth_getLogs is often capped at 10,000 blocks const fromBlock = latestBlock > blockRange ? latestBlock - blockRange : 0n; const transferLogs = await publicClient.getLogs({ address: IDENTITY_REGISTRY, event: parseAbiItem( "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)", ), args: { to: ownerWallet.address as `0x${string}` }, fromBlock, toBlock: latestBlock, }); if (transferLogs.length === 0) { throw new Error("No Transfer events found — registration may have failed"); } const agentId = transferLogs[transferLogs.length - 1].args.tokenId!.toString(); const identityContract = getContract({ address: IDENTITY_REGISTRY, abi: [\ {\ name: "ownerOf",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "address" }],\ },\ {\ name: "tokenURI",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "string" }],\ },\ ], client: publicClient, }); const owner = await identityContract.read.ownerOf([BigInt(agentId)]); const tokenURI = await identityContract.read.tokenURI([BigInt(agentId)]); console.log(`Agent ID: ${agentId}`); console.log(`Owner: ${owner}`); console.log(`Metadata: ${tokenURI}`); Your AI agent now has a unique onchain identity. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-6-record-reputation) Step 6. Record reputation ------------------------------------------------------------------------------------------------------------------------------ Build your agent’s reputation by recording feedback. Use the **validator wallet** — per ERC-8004, agent owners cannot record reputation for their own agents. index.ts index.py import { keccak256, toHex } from "viem"; const REPUTATION_REGISTRY = "0x8004B663056A597Dffe9eCcC1965A193B7388713"; const tag = "successful_trade"; const feedbackHash = keccak256(toHex(tag)); const reputationTx = await circleClient.createContractExecutionTransaction({ walletAddress: validatorWallet.address!, blockchain: "ARC-TESTNET", contractAddress: REPUTATION_REGISTRY, abiFunctionSignature: "giveFeedback(uint256,int128,uint8,string,string,string,string,bytes32)", abiParameters: [agentId, "95", "0", tag, "", "", "", feedbackHash], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); // Poll until confirmed (same pattern as Step 4) **Production scoring**: This quickstart hardcodes `score: 95` for demonstration. In production, calculate scores dynamically based on agent behavior. For example, `score = loanRepaidOnTime ? 100 : 20` for lending protocols, or `score = slippagePct < 1 ? 95 : 60` for trading platforms.The ReputationRegistry stores attestations from external observers who witnessed the agent’s actions. Your application logic calculates scores based on outcomes, then records them onchain. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-7-request-and-verify-validation) Step 7. Request and verify validation ------------------------------------------------------------------------------------------------------------------------------------------------------ The ERC-8004 ValidationRegistry uses a two-step request/response flow. The **agent owner** requests validation from a validator, then the **validator** submits a response. index.ts index.py const VALIDATION_REGISTRY = "0x8004Cb1BF31DAf7788923b405b754f57acEB4272"; const requestURI = "ipfs://bafkreiexamplevalidationrequest"; const requestHash = keccak256( toHex(`kyc_verification_request_agent_${agentId}`), ); // Owner requests validation const validationReqTx = await circleClient.createContractExecutionTransaction({ walletAddress: ownerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: VALIDATION_REGISTRY, abiFunctionSignature: "validationRequest(address,uint256,string,bytes32)", abiParameters: [validatorWallet.address!, agentId, requestURI, requestHash], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); // Poll until confirmed (same pattern as Step 4) // Validator responds (100 = passed, 0 = failed) const validationResTx = await circleClient.createContractExecutionTransaction({ walletAddress: validatorWallet.address!, blockchain: "ARC-TESTNET", contractAddress: VALIDATION_REGISTRY, abiFunctionSignature: "validationResponse(bytes32,uint8,string,bytes32,string)", abiParameters: [\ requestHash,\ "100",\ "",\ "0x" + "0".repeat(64),\ "kyc_verified",\ ], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); // Poll until confirmed, then verify: const validationContract = getContract({ address: VALIDATION_REGISTRY, abi: [\ {\ name: "getValidationStatus",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "requestHash", type: "bytes32" }],\ outputs: [\ { name: "validatorAddress", type: "address" },\ { name: "agentId", type: "uint256" },\ { name: "response", type: "uint8" },\ { name: "responseHash", type: "bytes32" },\ { name: "tag", type: "string" },\ { name: "lastUpdate", type: "uint256" },\ ],\ },\ ], client: publicClient, }); type ValidationStatus = readonly [\ `0x${string}`,\ bigint,\ number,\ `0x${string}`,\ string,\ bigint,\ ]; const [valAddr, , response, , tag] = (await validationContract.read.getValidationStatus([\ requestHash,\ ])) as ValidationStatus; console.log(`Validator: ${valAddr}`); console.log(`Response: ${response} (100 = passed)`); console.log(`Tag: ${tag}`); [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#full-agent-registration-script) Full agent registration script ----------------------------------------------------------------------------------------------------------------------------------------- The complete script below combines all the preceding steps into a single runnable file. index.ts index.py import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; import { createPublicClient, http, parseAbiItem, getContract, keccak256, toHex, } from "viem"; import { arcTestnet } from "viem/chains"; const IDENTITY_REGISTRY = "0x8004A818BFB912233c491871b3d84c89A494BD9e"; const REPUTATION_REGISTRY = "0x8004B663056A597Dffe9eCcC1965A193B7388713"; const VALIDATION_REGISTRY = "0x8004Cb1BF31DAf7788923b405b754f57acEB4272"; const METADATA_URI = process.env.METADATA_URI || "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei"; const circleClient = initiateDeveloperControlledWalletsClient({ apiKey: process.env.CIRCLE_API_KEY!, entitySecret: process.env.CIRCLE_ENTITY_SECRET!, }); const publicClient = createPublicClient({ chain: arcTestnet, transport: http(), }); // Helper functions async function waitForTransaction(txId: string, label: string) { process.stdout.write(` Waiting for ${label}`); for (let i = 0; i < 30; i++) { await new Promise((r) => setTimeout(r, 2000)); const { data } = await circleClient.getTransaction({ id: txId }); if (data?.transaction?.state === "COMPLETE") { const txHash = data.transaction.txHash; console.log(` ✓\n Tx: https://testnet.arcscan.app/tx/${txHash}`); return txHash; } if (data?.transaction?.state === "FAILED") { throw new Error(`${label} failed onchain`); } process.stdout.write("."); } throw new Error(`${label} timed out`); } // Main invocation async function main() { console.log("\n── Step 1: Create wallets ──"); const walletSet = await circleClient.createWalletSet({ name: "ERC8004 Agent Wallets", }); const walletsResponse = await circleClient.createWallets({ blockchains: ["ARC-TESTNET"], count: 2, walletSetId: walletSet.data?.walletSet?.id ?? "", accountType: "SCA", }); const ownerWallet = walletsResponse.data?.wallets?.[0]!; const validatorWallet = walletsResponse.data?.wallets?.[1]!; console.log(` Owner: ${ownerWallet.address} (${ownerWallet.id})`); console.log( ` Validator: ${validatorWallet.address} (${validatorWallet.id})`, ); console.log("\n── Step 2: Register agent identity ──"); console.log(` Metadata URI: ${METADATA_URI}`); const registerTx = await circleClient.createContractExecutionTransaction({ walletAddress: ownerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: IDENTITY_REGISTRY, abiFunctionSignature: "register(string)", abiParameters: [METADATA_URI], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction(registerTx.data?.id!, "registration"); console.log("\n── Step 3: Retrieve agent ID ──"); const latestBlock = await publicClient.getBlockNumber(); const blockRange = 10000n; // RPC limit: eth_getLogs is often capped at 10,000 blocks const fromBlock = latestBlock > blockRange ? latestBlock - blockRange : 0n; const transferLogs = await publicClient.getLogs({ address: IDENTITY_REGISTRY, event: parseAbiItem( "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)", ), args: { to: ownerWallet.address as `0x${string}` }, fromBlock, toBlock: latestBlock, }); if (transferLogs.length === 0) { throw new Error("No Transfer events found — registration may have failed"); } const agentId = transferLogs[transferLogs.length - 1].args.tokenId!.toString(); const identityContract = getContract({ address: IDENTITY_REGISTRY, abi: [\ {\ name: "ownerOf",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "address" }],\ },\ {\ name: "tokenURI",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "string" }],\ },\ ], client: publicClient, }); const owner = await identityContract.read.ownerOf([BigInt(agentId)]); const tokenURI = await identityContract.read.tokenURI([BigInt(agentId)]); console.log(` Agent ID: ${agentId}`); console.log(` Owner: ${owner}`); console.log(` Metadata URI: ${tokenURI}`); console.log("\n── Step 4: Record reputation ──"); const tag = "successful_trade"; const feedbackHash = keccak256(toHex(tag)); const reputationTx = await circleClient.createContractExecutionTransaction({ walletAddress: validatorWallet.address!, blockchain: "ARC-TESTNET", contractAddress: REPUTATION_REGISTRY, abiFunctionSignature: "giveFeedback(uint256,int128,uint8,string,string,string,string,bytes32)", abiParameters: [agentId, "95", "0", tag, "", "", "", feedbackHash], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }); await waitForTransaction(reputationTx.data?.id!, "reputation"); console.log("\n── Step 5: Verify reputation ──"); const reputationLogs = await publicClient.getLogs({ address: REPUTATION_REGISTRY, fromBlock: latestBlock - 1000n, toBlock: "latest", }); console.log(` Found ${reputationLogs.length} feedback event(s)`); // Owner requests; validator responds per ERC-8004 console.log("\n── Step 6: Request validation ──"); const requestURI = "ipfs://bafkreiexamplevalidationrequest"; const requestHash = keccak256( toHex(`kyc_verification_request_agent_${agentId}`), ); const validationReqTx = await circleClient.createContractExecutionTransaction( { walletAddress: ownerWallet.address!, blockchain: "ARC-TESTNET", contractAddress: VALIDATION_REGISTRY, abiFunctionSignature: "validationRequest(address,uint256,string,bytes32)", abiParameters: [\ validatorWallet.address!,\ agentId,\ requestURI,\ requestHash,\ ], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }, ); await waitForTransaction(validationReqTx.data?.id!, "validation request"); // Validator responds; 100 = passed, 0 = failed console.log("\n── Step 7: Validation response ──"); const validationResTx = await circleClient.createContractExecutionTransaction( { walletAddress: validatorWallet.address!, blockchain: "ARC-TESTNET", contractAddress: VALIDATION_REGISTRY, abiFunctionSignature: "validationResponse(bytes32,uint8,string,bytes32,string)", abiParameters: [\ requestHash,\ "100",\ "",\ "0x" + "0".repeat(64),\ "kyc_verified",\ ], fee: { type: "level", config: { feeLevel: "MEDIUM" } }, }, ); await waitForTransaction(validationResTx.data?.id!, "validation response"); console.log("\n── Step 8: Check validation ──"); const validationContract = getContract({ address: VALIDATION_REGISTRY, abi: [\ {\ name: "getValidationStatus",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "requestHash", type: "bytes32" }],\ outputs: [\ { name: "validatorAddress", type: "address" },\ { name: "agentId", type: "uint256" },\ { name: "response", type: "uint8" },\ { name: "responseHash", type: "bytes32" },\ { name: "tag", type: "string" },\ { name: "lastUpdate", type: "uint256" },\ ],\ },\ ], client: publicClient, }); type ValidationStatus = readonly [\ `0x${string}`,\ bigint,\ number,\ `0x${string}`,\ string,\ bigint,\ ]; const [valAddr, , valResponse, , valTag] = (await validationContract.read.getValidationStatus([\ requestHash,\ ])) as ValidationStatus; console.log(` Validator: ${valAddr}`); console.log(` Response: ${valResponse} (100 = passed)`); console.log(` Tag: ${valTag}`); console.log("\n── Complete ──"); console.log(" ✓ Identity registered"); console.log(" ✓ Reputation recorded"); console.log(" ✓ Validation requested and verified"); console.log( `\n Explorer: https://testnet.arcscan.app/address/${ownerWallet.address}\n`, ); } main().catch((error) => { console.error("\nError:", error.message ?? error); process.exit(1); }); See all 266 lines Save it, then run: Node.js Python npm run start If you followed the Python workflow, run `deactivate` when you’re done to exit the virtual environment. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#prerequisites-2) Prerequisites --------------------------------------------------------------------------------------------------------- Before you begin, make sure you have: 1. Installed [Node.js v22+](https://nodejs.org/) 2. Two self-managed EVM wallets for Arc Testnet * Testnet USDC in both wallets to pay for gas [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-1-set-up-your-project-2) Step 1. Set up your project ------------------------------------------------------------------------------------------------------------------------------------ Create a project directory, install dependencies, and configure your environment. ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#1-1-create-the-project-and-install-dependencies-2) 1.1. Create the project and install dependencies mkdir erc8004-quickstart cd erc8004-quickstart npm init -y npm pkg set type=module npm pkg set scripts.start="tsx --env-file=.env index.ts" npm install viem npm install --save-dev tsx typescript @types/node ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#1-2-configure-typescript-optional-2) 1.2. Configure TypeScript (optional) This step is optional. It helps prevent missing types in your IDE or editor. Create a `tsconfig.json` file: npx tsc --init Then, update the `tsconfig.json` file: cat <<'EOF' > tsconfig.json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["node"] } } EOF ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#1-3-set-environment-variables-2) 1.3. Set environment variables Create a `.env` file in the project directory: .env OWNER_PRIVATE_KEY=0xYOUR_OWNER_PRIVATE_KEY VALIDATOR_PRIVATE_KEY=0xYOUR_VALIDATOR_PRIVATE_KEY * `OWNER_PRIVATE_KEY` is the `0x`\-prefixed private key for the Arc Testnet wallet that owns the agent and requests validation. * `VALIDATOR_PRIVATE_KEY` is the `0x`\-prefixed private key for the Arc Testnet wallet that records reputation and submits the validation response. The `npm run start` command loads variables from `.env` using Node.js native env-file support. Prefer editing `.env` files in your IDE or editor so credentials are not leaked to your shell history. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-2-prepare-your-wallets) Step 2. Prepare your wallets ------------------------------------------------------------------------------------------------------------------------------------ In this step, you prepare two self-managed Arc Testnet wallets for the ERC-8004 flow. One wallet owns the agent and the other records reputation. If you already have two funded Arc Testnet wallets for this flow, skip to [Step 3](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-3-prepare-agent-metadata-2) . Per ERC-8004, agent owners cannot record reputation for their own agents to prevent self-dealing.The Step 2 through 7 code snippets explain the flow in smaller pieces. They are not cumulative and will not run if pasted together. To run the full workflow end to end, use the [complete script](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#full-agent-registration-script-2) at the end of this tutorial. ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#2-1-create-or-fund-your-wallets) 2.1. Create or fund your wallets Create two self-managed EVM wallets if you do not already have them. For example, you can generate throwaway wallets with Foundry: cast wallet new --json Run it twice, once for the owner wallet and once for the validator wallet, then fund both wallets with Arc Testnet USDC so they can submit transactions. ### [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#2-2-confirm-wallet-roles) 2.2. Confirm wallet roles * the owner wallet registers the agent identity and requests validation * the validator wallet records reputation and submits the validation response [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-3-prepare-agent-metadata-2) Step 3. Prepare agent metadata ------------------------------------------------------------------------------------------------------------------------------------------ Create a JSON file with metadata for your agent. The structure below is an example you can adapt for your use case. ERC-8004 registration stores a metadata URI, but the JSON fields at that URI are application-defined unless your integration follows a separate metadata convention. agent-metadata.json { "name": "DeFi Arbitrage Agent v1.0", "description": "Autonomous trading agent for cross-DEX arbitrage on Arc", "image": "ipfs://QmAgentAvatarHash...", "agent_type": "trading", "capabilities": [\ "arbitrage_detection",\ "liquidity_monitoring",\ "automated_execution"\ ], "version": "1.0.0" } Upload to IPFS using [Pinata](https://pinata.cloud/) , [NFT.Storage](https://nft.storage/) , [Web3.Storage](https://web3.storage/) or your preferred IPFS tool. You’ll receive an IPFS URI like `ipfs://QmYourHash...`. For this quickstart, you can skip uploading and use the example URI: `ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei` [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-4-register-your-agent-identity-2) Step 4. Register your agent identity ------------------------------------------------------------------------------------------------------------------------------------------------------ Call `register(metadataURI)` on the IdentityRegistry to mint an identity NFT for your agent. index.ts import { createPublicClient, createWalletClient, http, getContract, } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { arcTestnet } from "viem/chains"; const IDENTITY_REGISTRY = "0x8004A818BFB912233c491871b3d84c89A494BD9e"; const METADATA_URI = process.env.METADATA_URI || "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei"; const ownerAccount = privateKeyToAccount( process.env.OWNER_PRIVATE_KEY as `0x${string}`, ); const publicClient = createPublicClient({ chain: arcTestnet, transport: http(), }); const ownerWalletClient = createWalletClient({ account: ownerAccount, chain: arcTestnet, transport: http(), }); const identityContract = getContract({ address: IDENTITY_REGISTRY, abi: [\ {\ name: "register",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [{ name: "metadataURI", type: "string" }],\ outputs: [],\ },\ ], client: { public: publicClient, wallet: ownerWalletClient }, }); const registerTx = await identityContract.write.register([METADATA_URI], { account: ownerAccount, }); await publicClient.waitForTransactionReceipt({ hash: registerTx }); console.log(`Registered: https://testnet.arcscan.app/tx/${registerTx}`); [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-5-retrieve-your-agent-id-2) Step 5. Retrieve your agent ID ------------------------------------------------------------------------------------------------------------------------------------------ Query the `Transfer` event from the IdentityRegistry to find the token ID minted for your agent. index.ts import { parseAbiItem } from "viem"; const latestBlock = await publicClient.getBlockNumber(); const blockRange = 10000n; const fromBlock = latestBlock > blockRange ? latestBlock - blockRange : 0n; const transferLogs = await publicClient.getLogs({ address: IDENTITY_REGISTRY, event: parseAbiItem( "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)", ), args: { to: ownerAccount.address }, fromBlock, toBlock: latestBlock, }); if (transferLogs.length === 0) { throw new Error("No Transfer events found — registration may have failed"); } const agentId = transferLogs[transferLogs.length - 1].args.tokenId!; const identityReadContract = getContract({ address: IDENTITY_REGISTRY, abi: [\ {\ name: "ownerOf",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "address" }],\ },\ {\ name: "tokenURI",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "string" }],\ },\ ], client: publicClient, }); const owner = await identityReadContract.read.ownerOf([agentId]); const tokenURI = await identityReadContract.read.tokenURI([agentId]); console.log(`Agent ID: ${agentId}`); console.log(`Owner: ${owner}`); console.log(`Metadata URI: ${tokenURI}`); Your AI agent now has a unique onchain identity. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-6-record-reputation-2) Step 6. Record reputation -------------------------------------------------------------------------------------------------------------------------------- Build your agent’s reputation by recording feedback. Use the **validator wallet** — per ERC-8004, agent owners cannot record reputation for their own agents. index.ts import { keccak256, toHex } from "viem"; const REPUTATION_REGISTRY = "0x8004B663056A597Dffe9eCcC1965A193B7388713"; const validatorAccount = privateKeyToAccount( process.env.VALIDATOR_PRIVATE_KEY as `0x${string}`, ); const validatorWalletClient = createWalletClient({ account: validatorAccount, chain: arcTestnet, transport: http(), }); const tag = "successful_trade"; const feedbackHash = keccak256(toHex(tag)); const reputationContract = getContract({ address: REPUTATION_REGISTRY, abi: [\ {\ name: "giveFeedback",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "agentId", type: "uint256" },\ { name: "score", type: "int128" },\ { name: "feedbackType", type: "uint8" },\ { name: "tag", type: "string" },\ { name: "metadataURI", type: "string" },\ { name: "evidenceURI", type: "string" },\ { name: "comment", type: "string" },\ { name: "feedbackHash", type: "bytes32" },\ ],\ outputs: [],\ },\ ], client: { public: publicClient, wallet: validatorWalletClient }, }); const reputationTx = await reputationContract.write.giveFeedback( [agentId, 95n, 0, tag, "", "", "", feedbackHash], { account: validatorAccount }, ); await publicClient.waitForTransactionReceipt({ hash: reputationTx }); console.log(`Reputation: https://testnet.arcscan.app/tx/${reputationTx}`); **Production scoring**: This quickstart hardcodes `score: 95` for demonstration. In production, calculate scores dynamically based on agent behavior. For example, `score = loanRepaidOnTime ? 100 : 20` for lending protocols, or `score = slippagePct < 1 ? 95 : 60` for trading platforms.The ReputationRegistry stores attestations from external observers who witnessed the agent’s actions. Your application logic calculates scores based on outcomes, then records them onchain. [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#step-7-request-and-verify-validation-2) Step 7. Request and verify validation -------------------------------------------------------------------------------------------------------------------------------------------------------- The ERC-8004 ValidationRegistry uses a two-step request/response flow. The **agent owner** requests validation from a validator, then the **validator** submits a response. index.ts const VALIDATION_REGISTRY = "0x8004Cb1BF31DAf7788923b405b754f57acEB4272"; const requestURI = "ipfs://bafkreiexamplevalidationrequest"; const requestHash = keccak256( toHex(`kyc_verification_request_agent_${agentId}`), ); const validationContract = getContract({ address: VALIDATION_REGISTRY, abi: [\ {\ name: "validationRequest",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "validator", type: "address" },\ { name: "agentId", type: "uint256" },\ { name: "requestURI", type: "string" },\ { name: "requestHash", type: "bytes32" },\ ],\ outputs: [],\ },\ {\ name: "validationResponse",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "requestHash", type: "bytes32" },\ { name: "response", type: "uint8" },\ { name: "responseURI", type: "string" },\ { name: "responseHash", type: "bytes32" },\ { name: "tag", type: "string" },\ ],\ outputs: [],\ },\ {\ name: "getValidationStatus",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "requestHash", type: "bytes32" }],\ outputs: [\ { name: "validatorAddress", type: "address" },\ { name: "agentId", type: "uint256" },\ { name: "response", type: "uint8" },\ { name: "responseHash", type: "bytes32" },\ { name: "tag", type: "string" },\ { name: "lastUpdate", type: "uint256" },\ ],\ },\ ], client: publicClient, }); const validationRequestTx = await ownerWalletClient.writeContract({ address: VALIDATION_REGISTRY, abi: validationContract.abi, functionName: "validationRequest", args: [validatorAccount.address, agentId, requestURI, requestHash], account: ownerAccount, }); await publicClient.waitForTransactionReceipt({ hash: validationRequestTx }); const validationResponseTx = await validatorWalletClient.writeContract({ address: VALIDATION_REGISTRY, abi: validationContract.abi, functionName: "validationResponse", args: [requestHash, 100, "", `0x${"0".repeat(64)}`, "kyc_verified"], account: validatorAccount, }); await publicClient.waitForTransactionReceipt({ hash: validationResponseTx }); type ValidationStatus = readonly [\ `0x${string}`,\ bigint,\ number,\ `0x${string}`,\ string,\ bigint,\ ]; const [valAddr, , response, , tag] = (await validationContract.read.getValidationStatus([\ requestHash,\ ])) as ValidationStatus; console.log(`Validator: ${valAddr}`); console.log(`Response: ${response} (100 = passed)`); console.log(`Tag: ${tag}`); [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#full-agent-registration-script-2) Full agent registration script ------------------------------------------------------------------------------------------------------------------------------------------- The complete script below combines all the preceding steps into a single runnable file. index.ts import { createPublicClient, createWalletClient, getContract, http, keccak256, parseAbiItem, toHex, } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { arcTestnet } from "viem/chains"; const IDENTITY_REGISTRY = "0x8004A818BFB912233c491871b3d84c89A494BD9e"; const REPUTATION_REGISTRY = "0x8004B663056A597Dffe9eCcC1965A193B7388713"; const VALIDATION_REGISTRY = "0x8004Cb1BF31DAf7788923b405b754f57acEB4272"; const METADATA_URI = process.env.METADATA_URI || "ipfs://bafkreibdi6623n3xpf7ymk62ckb4bo75o3qemwkpfvp5i25j66itxvsoei"; const ownerAccount = privateKeyToAccount( process.env.OWNER_PRIVATE_KEY as `0x${string}`, ); const validatorAccount = privateKeyToAccount( process.env.VALIDATOR_PRIVATE_KEY as `0x${string}`, ); const publicClient = createPublicClient({ chain: arcTestnet, transport: http(), }); const ownerWalletClient = createWalletClient({ account: ownerAccount, chain: arcTestnet, transport: http(), }); const validatorWalletClient = createWalletClient({ account: validatorAccount, chain: arcTestnet, transport: http(), }); const identityAbi = [\ {\ name: "register",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [{ name: "metadataURI", type: "string" }],\ outputs: [],\ },\ {\ name: "ownerOf",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "address" }],\ },\ {\ name: "tokenURI",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "tokenId", type: "uint256" }],\ outputs: [{ name: "", type: "string" }],\ },\ ] as const; const reputationAbi = [\ {\ name: "giveFeedback",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "agentId", type: "uint256" },\ { name: "score", type: "int128" },\ { name: "feedbackType", type: "uint8" },\ { name: "tag", type: "string" },\ { name: "metadataURI", type: "string" },\ { name: "evidenceURI", type: "string" },\ { name: "comment", type: "string" },\ { name: "feedbackHash", type: "bytes32" },\ ],\ outputs: [],\ },\ ] as const; const validationAbi = [\ {\ name: "validationRequest",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "validator", type: "address" },\ { name: "agentId", type: "uint256" },\ { name: "requestURI", type: "string" },\ { name: "requestHash", type: "bytes32" },\ ],\ outputs: [],\ },\ {\ name: "validationResponse",\ type: "function",\ stateMutability: "nonpayable",\ inputs: [\ { name: "requestHash", type: "bytes32" },\ { name: "response", type: "uint8" },\ { name: "responseURI", type: "string" },\ { name: "responseHash", type: "bytes32" },\ { name: "tag", type: "string" },\ ],\ outputs: [],\ },\ {\ name: "getValidationStatus",\ type: "function",\ stateMutability: "view",\ inputs: [{ name: "requestHash", type: "bytes32" }],\ outputs: [\ { name: "validatorAddress", type: "address" },\ { name: "agentId", type: "uint256" },\ { name: "response", type: "uint8" },\ { name: "responseHash", type: "bytes32" },\ { name: "tag", type: "string" },\ { name: "lastUpdate", type: "uint256" },\ ],\ },\ ] as const; type ValidationStatus = readonly [\ `0x${string}`,\ bigint,\ number,\ `0x${string}`,\ string,\ bigint,\ ]; async function waitForReceipt(hash: `0x${string}`, label: string) { console.log(` Waiting for ${label}: ${hash}`); const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log(` ${label} confirmed in block ${receipt.blockNumber}`); console.log(` Explorer: https://testnet.arcscan.app/tx/${hash}`); return receipt; } async function main() { console.log("\n── Step 1: Prepare wallets ──"); console.log(` Owner: ${ownerAccount.address}`); console.log(` Validator: ${validatorAccount.address}`); console.log("\n── Step 2: Register agent identity ──"); console.log(` Metadata URI: ${METADATA_URI}`); const registerTx = await ownerWalletClient.writeContract({ address: IDENTITY_REGISTRY, abi: identityAbi, functionName: "register", args: [METADATA_URI], account: ownerAccount, }); const receipt = await waitForReceipt(registerTx, "Registration"); console.log("\n── Step 3: Retrieve agent ID ──"); const transferLogs = await publicClient.getLogs({ address: IDENTITY_REGISTRY, event: parseAbiItem( "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)", ), args: { to: ownerAccount.address }, fromBlock: receipt.blockNumber, toBlock: receipt.blockNumber, }); if (transferLogs.length === 0) { throw new Error("No Transfer events found in the registration block"); } const agentId = transferLogs[transferLogs.length - 1].args.tokenId; if (agentId == null) { throw new Error("Registration event did not include a tokenId"); } const identityContract = getContract({ address: IDENTITY_REGISTRY, abi: identityAbi, client: publicClient, }); const owner = await identityContract.read.ownerOf([agentId]); const tokenURI = await identityContract.read.tokenURI([agentId]); console.log(` Agent ID: ${agentId}`); console.log(` Owner: ${owner}`); console.log(` Metadata URI: ${tokenURI}`); console.log("\n── Step 4: Record reputation ──"); const tag = "successful_trade"; const feedbackHash = keccak256(toHex(tag)); const reputationContract = getContract({ address: REPUTATION_REGISTRY, abi: reputationAbi, client: { public: publicClient, wallet: validatorWalletClient }, }); const reputationTx = await reputationContract.write.giveFeedback( [agentId, 95n, 0, tag, "", "", "", feedbackHash], { account: validatorAccount }, ); const reputationReceipt = await waitForReceipt(reputationTx, "Reputation"); console.log("\n── Step 5: Verify reputation ──"); const fromBlock = reputationReceipt.blockNumber > 1000n ? reputationReceipt.blockNumber - 1000n : 0n; const reputationLogs = await publicClient.getLogs({ address: REPUTATION_REGISTRY, fromBlock, toBlock: "latest", }); console.log(` Found ${reputationLogs.length} feedback event(s)`); console.log("\n── Step 6: Request validation ──"); const requestURI = "ipfs://bafkreiexamplevalidationrequest"; const requestHash = keccak256( toHex(`kyc_verification_request_agent_${agentId}`), ); const validationRequestContract = getContract({ address: VALIDATION_REGISTRY, abi: validationAbi, client: { public: publicClient, wallet: ownerWalletClient }, }); const validationRequestTx = await validationRequestContract.write.validationRequest( [validatorAccount.address, agentId, requestURI, requestHash], { account: ownerAccount }, ); await waitForReceipt(validationRequestTx, "Validation request"); console.log("\n── Step 7: Validation response ──"); const validationResponseContract = getContract({ address: VALIDATION_REGISTRY, abi: validationAbi, client: { public: publicClient, wallet: validatorWalletClient }, }); const validationResponseTx = await validationResponseContract.write.validationResponse( [\ requestHash,\ 100,\ "",\ `0x${"0".repeat(64)}` as `0x${string}`,\ "kyc_verified",\ ], { account: validatorAccount }, ); await waitForReceipt(validationResponseTx, "Validation response"); console.log("\n── Step 8: Check validation ──"); const validationReadContract = getContract({ address: VALIDATION_REGISTRY, abi: validationAbi, client: publicClient, }); const [valAddr, , response, , validationTag] = (await validationReadContract.read.getValidationStatus([\ requestHash,\ ])) as ValidationStatus; console.log(` Validator: ${valAddr}`); console.log(` Response: ${response} (100 = passed)`); console.log(` Tag: ${validationTag}`); console.log("\n── Complete ──"); console.log(" ✓ Identity registered"); console.log(" ✓ Reputation recorded"); console.log(" ✓ Validation requested and verified"); } main().catch((error) => { console.error("\nError:", error.message ?? error); process.exit(1); }); See all 300 lines Save it, then run: npm run start [​](https://docs.arc.network/arc/tutorials/register-your-first-ai-agent#summary) Summary ------------------------------------------------------------------------------------------- After completing this quickstart, you’ve successfully: * Created or prepared two Arc Testnet wallets for the ERC-8004 flow * Registered an AI agent with a unique onchain identity (ERC-721 token) * Recorded reputation feedback from an external validator * Requested validation from a validator and verified the response onchain Was this page helpful? YesNo [Monitor contract events](https://docs.arc.network/arc/tutorials/monitor-contract-events) [Create your first ERC-8183 job](https://docs.arc.network/arc/tutorials/create-your-first-erc-8183-job) ⌘I Assistant Responses are generated using AI and may contain mistakes. ---