Use this flow to send USDC with a connected browser wallet. The example uses Arc
Testnet.Prerequisites
Before you begin, ensure that you’ve:Step 1. Set up the project
1.1. Create the project and install dependencies
Create a new directory, install the App Kit packages, and add local browser demo
tooling:# Set up your directory and initialize a Node.js project
mkdir app-kit-send-browser-wallet
cd app-kit-send-browser-wallet
npm init -y
npm pkg set type=module
# Install App Kit packages
npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem {extraPackages}
# Install TypeScript and a local Vite dev server for the browser demo
npm install --save-dev typescript vite
This step is optional. It helps prevent missing types in your IDE or editor.
Create a tsconfig.json file:Then, update the tsconfig.json file:cat <<'EOF' > tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"types": ["node"]
}
}
EOF
Step 2. Connect a browser wallet
This step shows the core browser wallet integration flow: discover an
EIP-6963 provider, create an App
Kit adapter from the selected provider, and pass that adapter into an App Kit
SDK method.The snippets below keep wallet discovery, wallet connection, and adapter setup
in small helper functions for readability.2.1. Discover a browser wallet with EIP-6963
This pattern is standards-based. The example uses MetaMask as the selected
wallet, but the discovery flow works with any wallet that announces an
EIP-6963 provider.
import type { EIP1193Provider } from "viem";
type EIP6963ProviderInfo = {
uuid: string;
name: string;
icon: string;
rdns: string;
};
type EIP6963ProviderDetail = {
info: EIP6963ProviderInfo;
provider: EIP1193Provider;
};
declare global {
interface WindowEventMap {
"eip6963:announceProvider": CustomEvent<EIP6963ProviderDetail>;
}
}
async function discoverBrowserWallets(): Promise<EIP6963ProviderDetail[]> {
const providers = new Map<string, EIP6963ProviderDetail>();
const handleProviderAnnouncement = (
event: WindowEventMap["eip6963:announceProvider"],
) => {
providers.set(event.detail.info.uuid, event.detail);
};
window.addEventListener(
"eip6963:announceProvider",
handleProviderAnnouncement,
);
window.dispatchEvent(new Event("eip6963:requestProvider"));
await new Promise((resolve) => window.setTimeout(resolve, 250));
window.removeEventListener(
"eip6963:announceProvider",
handleProviderAnnouncement,
);
return [...providers.values()];
}
2.2. Connect the wallet and request account access
After you select a provider, request account access before calling an App Kit
SDK method. This should happen in a user-triggered action such as a
Connect wallet button.async function connectWallet(provider: EIP1193Provider) {
await provider.request({
method: "eth_requestAccounts",
params: undefined, // Required by the provider type even though this method has no params.
});
const accounts = (await provider.request({
method: "eth_accounts",
params: undefined, // Required by the provider type even though this method has no params.
})) as string[];
return {
connectedAddress: accounts[0] ?? null,
};
}
Keep wallet connection and App Kit actions as separate user actions. This avoids
overlapping wallet permission or chain-switch requests while a previous wallet
prompt is still pending.
2.3. Create a Viem adapter from the selected wallet provider
Use the discovered provider to request account access, then create the App Kit
adapter that signs transactions in the browser:import { createViemAdapterFromProvider } from "@circle-fin/adapter-viem-v2";
async function connectBrowserWallet() {
const providers = await discoverBrowserWallets();
const selectedWallet =
providers.find(
({ info }) => info.rdns === "io.metamask" || info.name === "MetaMask",
) ?? providers[0];
if (!selectedWallet) {
throw new Error("No EIP-6963 browser wallet found");
}
const { connectedAddress } = await connectWallet(selectedWallet.provider);
const adapter = await createViemAdapterFromProvider({
provider: selectedWallet.provider,
});
return {
adapter,
connectedAddress,
walletName: selectedWallet.info.name,
};
}
If multiple EVM wallets are installed, explicitly choose the wallet you want to
use instead of relying on the first announced provider. The browser demo used to
validate this quickstart prefers MetaMask when it is available.
Step 3. Send USDC
3.1. Call kit.send()
This is the only App Kit-specific send call you need after the wallet is
connected:import { AppKit } from "@circle-fin/app-kit";
import type { SendParams } from "@circle-fin/app-kit";
const kit = new AppKit();
async function sendUSDCWithBrowserWallet() {
const { adapter, connectedAddress, walletName } =
await connectBrowserWallet();
const sendParams: SendParams = {
from: { adapter, chain: "Arc_Testnet" },
to: "RECIPIENT_ADDRESS",
amount: "1.00",
token: "USDC",
};
const estimate = await kit.estimateSend(sendParams);
const result = await kit.send(sendParams);
console.log(`Submitted send with ${walletName}`, {
connectedAddress,
estimate,
result,
});
return result;
}
Using another
token or
blockchain? Change the token and
chain values in kit.send() and ensure the connected wallet holds enough
funds to complete the transfer. 3.2. Verify the transaction
After kit.send() resolves, inspect the returned result. Use the transaction
explorer URL to verify the amount and recipient on the blockchain.The following is an example of how the result of a successful send might look in
the browser console. The values are used in this example only and are not a real
transaction:{
name: "transfer",
state: "success",
txHash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
explorerUrl: "https://testnet.arcscan.app/tx/0x1234567890abcdef...",
}
Use this flow to send USDC with a developer-controlled wallet managed by Circle
Wallets. The example uses Arc Testnet.Prerequisites
Before you begin, ensure that you’ve:Step 1. Set up the project
1.1. Create the project and install dependencies
Create a new directory and install the App Kit SDK with the Circle Wallets
adapter and supporting tools:# Set up your directory and initialize a Node.js project
mkdir app-kit-send-circle-wallets
cd app-kit-send-circle-wallets
npm init -y
npm pkg set type=module
# Set up module type and start command
npm pkg set scripts.start="tsx --env-file=.env index.ts"
# Install runtime dependencies
npm install @circle-fin/app-kit @circle-fin/adapter-circle-wallets tsx
# Install dev dependencies
npm install --save-dev typescript @types/node
This step is optional. It helps prevent missing types in your IDE or editor.
Create a tsconfig.json file:Then, update the tsconfig.json file:cat <<'EOF' > tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"types": ["node"]
}
}
EOF
1.3. Set environment variables
Create an .env file in the project directory:Add your credentials. Replace YOUR_API_KEY with your Circle Developer API key,
YOUR_ENTITY_SECRET with your entity secret. You can fetch the address from the
Circle Developer Console
or the
list wallets
endpoint:CIRCLE_API_KEY=YOUR_API_KEY
CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET
Edit .env files in your IDE or editor so credentials are not leaked to your
shell history.
Step 2. Send USDC
2.1. Create the script
Create an index.ts file in the project directory and add the following code.
This code sends 1.00 USDC from your Circle Wallets-controlled Arc Testnet wallet
to a recipient on Arc Testnet:Using another
token or
blockchain? Change the token and
chain values in kit.send() and ensure the source wallet has enough funds to
complete the transfer. import { AppKit } from "@circle-fin/app-kit";
import { createCircleWalletsAdapter } from "@circle-fin/adapter-circle-wallets";
import type { SendParams } from "@circle-fin/app-kit";
const kit = new AppKit();
const sourceWalletAddress = "YOUR_SOURCE_WALLET_ADDRESS";
const recipientAddress = "RECIPIENT_ADDRESS";
const adapter = createCircleWalletsAdapter({
apiKey: process.env.CIRCLE_API_KEY!,
entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
});
const sendParams: SendParams = {
from: {
adapter,
chain: "Arc_Testnet",
address: sourceWalletAddress,
},
to: recipientAddress,
amount: "1.00",
token: "USDC",
};
const estimate = await kit.estimateSend(sendParams);
const result = await kit.send(sendParams);
console.dir({ estimate, result }, { depth: null, colors: true });
2.2. Run the script
Save the index.ts file and run the script in your terminal:2.3. Verify the transaction
After the script finishes, inspect the returned result in the terminal output.
Use the transaction explorer URL to verify the amount and recipient on the
blockchain.The following is an example of how the result of a successful send might look in
the terminal output. The values are used in this example only and are not a real
transaction:{
estimate: { gas: 406817n, fee: '8138073262135265', gasPrice: 20004260545n },
result: {
name: 'send',
state: 'success',
txHash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
explorerUrl: 'https://testnet.arcscan.app/tx/0x1234567890abcdef123456789...'
}
}