Skip to main content
This tutorial guides you through deploying smart contracts on Arc Testnet with Circle Contracts. You’ll create a Circle Dev-Controlled Wallet, fund it with the Circle Faucet, then deploy pre-audited contract templates (ERC-20, ERC-721, ERC-1155, Airdrop). 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 to review all templates and their options.

Prerequisites

To complete this tutorial, you need:
  1. Node.js v22+ installed
  2. Circle Developer Account - Sign up 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

Set up your environment

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.

Step 1: Set up your project

Set up your local environment and install the required dependencies.

1.1. Create a new project

Create a new directory. Navigate to it and start a new project with default settings.
mkdir hello-arc
cd hello-arc
npm init -y
npm pkg set type=module

1.2. Install dependencies

In the project directory, install the Circle Dev-Controlled Wallets SDK and the Circle Contracts SDK. 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 and Circle Contracts API directly if you can’t use the SDKs in your project.
npm install @circle-fin/developer-controlled-wallets @circle-fin/smart-contract-platform
npm install -D tsx typescript @types/node

1.3 Configure environment variables

Create a .env file in the project directory with your Circle credentials. Replace these placeholders with your own credentials:
  • CIRCLE_API_KEY: your API key should be either environment-prefixed (for example, TEST_API_KEY:abc123:def456 or LIVE_API_KEY:xyz:uvw) or base64-encoded strings.
  • CIRCLE_ENTITY_SECRET: your entity secret should be 64 lowercase alphanumeric characters.
  • CIRCLE_WEB3_API_KEY: (Python only) set to the same value as CIRCLE_API_KEY for Python SDK compatibility.
echo "CIRCLE_API_KEY={YOUR_API_KEY}
CIRCLE_ENTITY_SECRET={YOUR_ENTITY_SECRET}
CIRCLE_WEB3_API_KEY={YOUR_API_KEY}" > .env
Important: These are sensitive credentials. Do not commit them to version control or share them publicly.

Step 2: Set up your wallet

Create a dev-controlled wallet and fund it with testnet USDC. This covers gas fees for deploying your smart contract.

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. The wallet set is the source from which wallet keys are derived.
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",
});
Run the script:
npx tsx --env-file=.env create-wallet.ts
Response:
If you’re calling the API directly, you’ll need two requests. One to create the wallet set. 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 for you.
You should now have a newly created dev-controlled wallet. The API response will look similar to the following:
{
  "data": {
    "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"
      }
    ]
  }
}

2.2. Fund the wallet with testnet USDC

Use the Circle Faucet to get testnet USDC. You’ll need a funded balance to deploy contracts, mint tokens, and pay gas fees. To fund your wallet:
  1. Copy your wallet address from the response in step 2.1
  2. Visit faucet.circle.com
  3. Select Arc Testnet as the network
  4. Paste your wallet address
  5. Request testnet USDC

2.3. Check the wallet’s balance

You can check your wallet’s balance from the Developer Console. You can also check it by making a request to GET /wallets/{id}/balances with the wallet ID of the wallet you created.
const response = await client.getWalletTokenBalance({
  id: "<WALLET_ID>",
});

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.

Step 3: Prepare for deployment

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) or EOA (Externally Owned Account)
Note your wallet’s address for subsequent steps.

3.2. Understand deployment parameters

ParameterDescription
idempotencyKeyA unique value to prevent duplicate requests.
nameThe offchain contract name (visible in Circle Console only). Use MyTokenContract.
walletIdThe ID of the wallet deploying the contract. Use your dev-controlled wallet ID.
templateIdThe template identifier. Use a1b74add-23e0-4712-88d1-6b3009e85a86 for ERC-20. See Templates.
blockchainThe network to deploy onto. Use ARC-TESTNET.
entitySecretCiphertextThe re-encrypted entity secret. See Entity Secret Management.
feeLevelThe fee level for transaction processing. Use MEDIUM.
templateParametersThe onchain initialization parameters (see below).

3.3. Template parameters

Required Parameters:
ParameterTypeDescription
nameStringThe onchain contract name. Use MyToken.
defaultAdminStringThe address with administrator permissions. Use your Dev-Controlled Wallet address.
primarySaleRecipientStringThe address that receives proceeds from first-time sales. Use your wallet address.
Optional Parameters:
ParameterTypeDescription
symbolStringThe token symbol (for example, MTK).
platformFeeRecipientStringThe address that receives platform fees from sales. Set this when implementing platform fee revenue share.
platformFeePercentFloatThe platform fee percentage as decimal (for example, 0.1 for 10%). Requires platformFeeRecipient.
contractUriStringThe URL for the contract metadata.
trustedForwardersStrings[]A list of addresses that can forward ERC2771 meta-transactions to this contract.

Step 4: Deploy the smart contract

Deploy by making a request to POST /templates/{id}/deploy:
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";
import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform";

const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({
  apiKey: process.env.CIRCLE_API_KEY,
  entitySecret: process.env.CIRCLE_ENTITY_SECRET,
});

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",
    },
  },
});
Run the script:
npx tsx --env-file=.env deploy-erc20.ts
Response:
{
  "data": {
    "contractIds": ["xxxxxxxx-xxxx-7xxx-8xxx-xxxxxxxxxxxx"],
    "transactionId": "xxxxxxxx-xxxx-5xxx-axxx-xxxxxxxxxxxx"
  }
}
A successful response indicates deployment has been initiated, not completed. Use the transactionId to check the deployment status in the next step.

4.1. Check deployment status

You can check the status of the deployment from the Circle Developer Console or by calling GET /transactions/{id}:
const transactionResponse = await circleDeveloperSdk.getTransaction({
  id: "<TRANSACTION_ID>",
});
Response:
{
  "data": {
    "transaction": {
      "id": "601a0815-f749-41d8-b193-22cadd2a8977",
      "blockchain": "ARC-TESTNET",
      "state": "COMPLETE"
    }
  }
}

4.2. Get the contract address

After deployment completes, retrieve the contract address using GET /contracts/{id}:
const contractResponse = await circleContractSdk.getContract({
  id: response.data?.contractIds?.[0],
});
Response:
{
  "data": {
    "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 and on the Arc Testnet Explorer.
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.


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