Documentation Index
Fetch the complete documentation index at: https://circle-devdocs-test-ai-codegen-component.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
EURC provides the ability to transfer digital euros over public blockchains
using smart contracts. The smart contract lets you send, receive, and store
digital euros onchain with a wallet.
This guide demonstrates how to use the viem framework to
build a simple app that lets a user connect their wallet and interact with the
blockchain by sending a EURC transaction from their wallet address.
Prerequisites
Before you start building the sample app to perform a EURC transfer, make sure
you have:
-
Installed Node.js and npm. You can
download and install Node.js directly, or use a version
manager like nvm. The npm binary comes with
Node.js.
-
Installed MetaMask. You can
download and install MetaMask from their website. When
performing initial setup, you should create a wallet for the Ethereum Sepolia
testnet.
-
Testnet native tokens and testnet EURC in your wallet. You can get Sepolia ETH
(native token) from a
public faucet
and you can get Sepolia EURC from the
Circle Faucet.
Project setup
To begin building the sample app, first set up your project environment and
install dependencies:
- Create a new project directory and initialize a Node.js project:
mkdir eurc-transfer-app
cd eurc-transfer-app
npm init -y
- Install the required dependencies in your project directory:
npm install react@^18.2.0 \
react-dom@^18.2.0 \
@types/react@^18.0.27 \
@types/react-dom@^18.0.10 \
@vitejs/plugin-react@^3.1.0 \
typescript@^5.0.3 \
vite@^4.4.5
This sets up your development environment with the necessary libraries and tools
for building a React app with TypeScript and Vite.
- Install the viem library:
Build the transfer app
The following sections outline the relevant business logic of the example app.
You can view the full source for the app in the final section.
Set up public client
The public client is used to read blockchain data, such as transaction receipts
or token balances.
Configure the client to connect to the Sepolia testnet:
import { http, createPublicClient } from "viem";
import { sepolia } from "viem/chains";
const publicClient = createPublicClient({
chain: sepolia,
transport: http(),
});
Set up wallet client
The wallet client lets you interact with user accounts and sign transactions. To
connect it to MetaMask in the browser:
import { createWalletClient, custom } from "viem";
import { sepolia } from "viem/chains";
const walletClient = createWalletClient({
chain: sepolia,
transport: custom(window.ethereum!),
});
Define EURC contract details
Define the EURC contract address and the application binary interface (ABI). The
ABI specifies the functions available on the smart contract. Note that the EURC
token contract address varies by blockchain. This example uses the Ethereum
Sepolia contract address. For the full list of EURC smart contract addresses,
see EURC Contract Addresses.
const EURC_CONTRACT_ADDRESS = "0x08210f9170f89ab7658f0b5e3ff39b0e03c594d4";
const EURC_ABI = [
{
constant: false,
inputs: [
{ name: "_to", type: "address" },
{ name: "_value", type: "uint256" },
],
name: "transfer",
outputs: [{ name: "", type: "bool" }],
type: "function",
},
];
Connect wallet
Create a function to connect to the user’s wallet in MetaMask and retrieve the
wallet address:
const connect = async () => {
const [address] = await walletClient.requestAddresses();
setAccount(address);
};
Send transaction
Create a function to send the EURC transfer transaction. This function encodes
the transfer function data and sends the transaction to the blockchain using the
wallet client.
const data = encodeFunctionData({
abi: EURC_ABI,
functionName: "transfer",
args: [to, valueInWei],
});
const hash = await walletClient.sendTransaction({
account,
to: EURC_CONTRACT_ADDRESS,
data,
});
Wait for transaction receipt
Use the public client to wait for the transaction receipt, which confirms that
the transaction was included in a block.
useEffect(() => {
(async () => {
if (hash) {
const receipt = await publicClient.waitForTransactionReceipt({ hash });
setReceipt(receipt);
}
})();
}, [hash]);
Full source
Now that you understand the core steps for programmatically performing a EURC
transaction, create an index.tsx and index.html file in your project
directory and populate them with the sample code below. The resulting app
enables you to send EURC tokens from one wallet to another. The source wallet
must contain native testnet tokens (to pay for gas fees) and testnet EURC.
index.tsx
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom/client';
import {
http,
type Address,
type Hash,
type TransactionReceipt,
createPublicClient,
createWalletClient,
custom,
stringify,
encodeFunctionData,
} from 'viem';
import { sepolia } from 'viem/chains';
import 'viem/window';
const publicClient = createPublicClient({
chain: sepolia,
transport: http()
});
const walletClient = createWalletClient({
chain: sepolia,
transport: custom(window.ethereum!)
});
const EURC_CONTRACT_ADDRESS = '0x08210f9170f89ab7658f0b5e3ff39b0e03c594d4';
const EURC_ABI = [
{
constant: false,
inputs: [
{ name: '_to', type: 'address' },
{ name: '_value', type: 'uint256' },
],
name: 'transfer',
outputs: [{ name: '', type: 'bool' }],
type: 'function',
},
];
function Example() {
const [account, setAccount] = useState<Address>();
const [hash, setHash] = useState<Hash>();
const [receipt, setReceipt] = useState<TransactionReceipt>();
const addressInput = React.createRef<HTMLInputElement>();
const valueInput = React.createRef<HTMLInputElement>();
const connect = async () => {
const [address] = await walletClient.requestAddresses();
setAccount(address);
};
const sendTransaction = async () => {
if (!account) return;
const to = addressInput.current!.value as Address;
const value = valueInput.current!.value as `${number}`;
const valueInWei = BigInt(value) * BigInt(10 ** 6);
const data = encodeFunctionData({
abi: EURC_ABI,
functionName: 'transfer',
args: [to, valueInWei],
});
const hash = await walletClient.sendTransaction({
account,
to: EURC_CONTRACT_ADDRESS,
data,
});
setHash(hash);
};
useEffect(() => {
(async () => {
if (hash) {
const receipt = await publicClient.waitForTransactionReceipt({ hash });
setReceipt(receipt);
}
})();
}, [hash]);
if (account) {
return (
<>
<div>Connected: {account}</div>
<input ref={addressInput} placeholder="address" />
<input ref={valueInput} placeholder="value (EURC)" />
<button onClick={sendTransaction}>Send</button>
{receipt && (
<div>
Receipt: <pre><code>{stringify(receipt, null, 2)}</code></pre>
</div>
)}
</>
);
}
return <button onClick={connect}>Connect Wallet</button>;
}
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<Example />
);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>EURC Transfer Sample App</title>
</head>
<body>
<h1>EURC Transfer Sample App</h1>
<div id="root"></div>
<script type="module" src="/index.tsx"></script>
</body>
</html>
These two source files provide a complete demonstration app that you can use to
perform a EURC transfer from a MetaMask wallet. When you open the app, you can
connect your wallet, input the recipient address, and click Send to execute
the transaction on Ethereum Sepolia. The app provides a transaction receipt once
the transaction is included in a block.
Screenshots
Wallet connect screen:
Transfer screen: