> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# Token template

The Token template is an audited, ready-to-deploy smart contract for an ERC-20
token. The ERC-20 standard is the most popular standard for fungible tokens. The
token's fungibility allows it to be used for a variety of use cases, including:

* **Stablecoins:** ERC-20 tokens serve as the foundation for stablecoins like
  USDC, backed by US dollars. To learn more about the USDC contract, see
  [0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48](https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48)
  on Etherscan.

* **Loyalty points:** ERC-20 tokens can represent on-chain loyalty points to
  incentivize and reward users for their activities within a platform or
  ecosystem.

* **Governance:** ERC-20 tokens can represent governance rights, allowing
  holders to participate in protocol decisions. Notable examples include tokens
  utilized by platforms like Uniswap.

* **Ownership:** ERC-20 tokens can also represent fractional ownership in
  real-world assets, such as houses, ounces of gold, or company shares.

In this comprehensive guide, you explore the Token template, which provides all
the necessary information to deploy and understand the contract's common
functions.

## Deployment parameters

The Token template creates a customized, fully compliant ERC-20 smart contract.
To create a contract using this template, provide the following parameter values
when deploying a smart contract template using the
[`POST: /templates/{id}/deploy`](/api-reference/contracts/smart-contract-platform/deploy-contract-template)
API.

**Template ID:** a1b74add-23e0-4712-88d1-6b3009e85a86

### Template deployment parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `name` | String | X | Name of the contract - stored as a property of the contract on-chain.  |
| `symbol` | String | | Symbol of the token - stored on-chain. The symbol is usually 3 or 4 characters in length. |
| `defaultAdmin` | String | X | The address of the default admin. This address can execute permissioned functions on the contract. <br />**Important:** You will lose administrative access to the contract if this is not set to an address you control. |
| `primarySaleRecipient` | String | X | The recipient address for first-time sales.   |
| `platformFeeRecipient` | String | | The recipient address for all sales fees. If you deploy a template on someone else's behalf, you can set this to your own address. |
| `platformFeePercent` | Float | | The percentage of sales that go to the platform fee recipient. For example, set it as 0.1 if you want 10% of sales fees to go to the  `platformFeeRecipient`.  |
| `contractUri` | String | | The URL for the marketplace metadata of your contract. This is used on marketplaces like OpenSea. See [Contract-level Metadata](https://docs.opensea.io/docs/contract-level-metadata) for more information.  |
| `trustedForwarders` | Strings\[] | | A list of addresses that can forward ERC2771 meta-transactions to this contract. See [ethereum.org](https://eips.ethereum.org/EIPS/eip-2771) for more information.  |

Here is an example of the `templateParameters` JSON object within the request
body to
[deploy a contract from a template](/api-reference/contracts/smart-contract-platform/deploy-contract-template)
for the ERC-20 Token template.

<Note>
  In this example, the `defaultAdmin` and `primarySaleRecipient` parameters are
  the same address but can be set distinctly based on your use case.
</Note>

```json JSON theme={null}
"templateParameters": {
  "name": "My Token Contract",
  "defaultAdmin": "0x4F77E56dfA40990349e1078e97AC3Eb479e0dAc6",
  "primarySaleRecipient": "0x4F77E56dfA40990349e1078e97AC3Eb479e0dAc6"
}
```

## Common functions

This section lists the most commonly used functions on the Token template, their
respective parameters and potential failure scenarios. These functions include:

* [approve \[write\]](#approve-write)

* [transfer \[write\]](#transfer-write)

* [mintTo \[write\]](#mintto-write)

* [burn \[write\]](#burn-write)

* [grantRole \[write\]](#grantrole-write)

* [revokeRole \[write\]](#revokerole-write)

* [balanceOf \[read\]](#balanceof-write)

* [allowance \[read\]](#allowance-write)

<Note>
  At this time, not all failure scenarios or error messages received from the
  blockchain are passed through Circle's APIs. Instead, you will receive a
  generic
  [`ESTIMATION_ERROR`](/api-reference/contracts/error-codes#transaction-errors)
  error. If available, the `errorDetails` field will have more information on
  the cause of failure.
</Note>

## approve \[write]

The `approve` function lets token owners specify a limit on the number of tokens
another account address can spend on their behalf.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `spender` | address | The owner approves the account address to spend tokens. It could be another smart contract address or an externally owned account address. |
| `amount` | unit256 | The number of tokens the owner approves for spending by the specified spender. The amount should be set in the smallest denomination of the ERC-20 token. |

### Failure scenarios

* The approve function fails if the `spender` is the zero address.\
  *"ERC20: approve to the zero address"*

### Notes

* If `amount` is the maximum uint256 value the allowance is not updated when the
  `transferFrom` function is called. This is semantically equivalent to an
  infinite approval.

* There is no balance check on the `approve` function so token owners may
  approve allowances greater than their current balance.

```solidity Solidity theme={null}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
  address owner = _msgSender();
  _approve(owner, spender, amount);
  return true;
}
```

## transfer \[write]

Allows the token owner to transfer a specified number of tokens to another
account address.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `to` | address | The address to which the token will be transferred. This can be another user's address or a smart contract address. |
| `amount` | unit256 | The number of tokens to transfer. |

### Failure scenarios

* The `to` address parameter is checked to ensure it is not the zero address
  `address(0)`.\
  *"ERC20: transfer to the zero address"*
* The `beforeTokenTransfer` hook is called, which checks `TOKEN_TRANSFER`
  permissions.\
  "restricted to TRANSFER\_ROLE holders”
* The token owner doesn't have a sufficient balance to transfer the specified
  token amount.\
  *"ERC20: transfer amount exceeds balance"*

```solidity Solidity theme={null}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
  address owner = _msgSender();
  _transfer(owner, to, amount);
  return true;
}
```

## mintTo \[write]

A designated minter can create a specified number of tokens and assign them to a
specified account address.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `to` | address | The address to which the newly minted tokens will be assigned. |
| `amount` | unit256 | The number of tokens to be minted and assigned to the specified address. |

### Failure scenarios

* The function checks if the caller has the `MINTER_ROLE`. The function will
  fail if the caller does not have the minter role. Expect to see the following
  error:\
  *"not minter."*
* The function ensures that the account address is not the zero address
  `address(0)`, as this is an invalid address to mint tokens to.\
  *"ERC20: mint to the zero address"*
* The `beforeTokenTransfer` hook is called, which checks `TOKEN_TRANSFER`
  permissions.\
  *"restricted to* TRANSFER*ROLE \_holders”*

```solidity Solidity theme={null}
function mintTo(address to, uint256 amount) public virtual {
  require(hasRole(MINTER_ROLE, _msgSender()), "not minter.");
  _mintTo(to, amount);
}
```

## burn \[write]

Allows a token holder to burn (destroy) a specified number of the token total
supply.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `amount` | unit256 | The number of tokens to be burned. |

### Failure scenarios

* The `_beforeTokenTransfer`  hook is called, which checks `TOKEN_TRANSFER`
  permissions.\
  *"restricted to TRANSFER\_ROLE holders”*
* The token owner has no sufficient balance to burn the specified token
  amount.\
  *"ERC20: burn amount exceeds balance"*

```solidity Solidity theme={null}
function burn(uint256 amount) public virtual {
  _burn(_msgSender(), amount);
}
```

### Permissions and roles

Roles are referred to by their `bytes32` identifier. For example:

```solidity Solidity theme={null}
bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
```

Roles can also represent a set of permissions. To restrict access to a function
call, use `hasRole`:

```solidity Solidity theme={null}
function foo() public {
  require(hasRole(MY_ROLE, msg.sender));
  ...
}
```

Roles can be granted and revoked dynamically via the `grantRole` and
`revokeRole` functions. Each role has an associated admin role, and only
accounts that have a role's admin role can call `grantRole` and `revokeRole`. By
default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`. Only accounts
with the `DEFAULT_ADMIN_ROLE` can grant or revoke other roles. You can use the
`_setRoleAdmin` function to create more complex role relationships.

## grantRole \[write]

Grants a specified role to an account. Only an account address that has the
admin role assigned can call this function.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `role` | bytes32 | The bytes32 identifier of the role to be granted. |
| `account` | address | The address to which the role will be granted. |

### Failure scenarios

* The `onlyRole(getRoleAdmin(role))` modifier ensures that the function caller
  has the admin role for the specified role. Only addresses with the admin role
  can grant roles to other accounts.\
  *"AccessControl: account ", StringsUpgradeable.toHexString(account), " is
  missing role ", StringsUpgradeable.toHexString(uint256(role), 32)*
* The function checks if the account already has the specified role using the
  `hasRole` function. If the account does not have the role, the function
  continues. There is no error message.

```solidity Solidity theme={null}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
  _grantRole(role, account);
}
```

## revokeRole \[write]

Revoke the specified role from an account address. Only account addresses with
the admin role assigned can call this function.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `role` | bytes32 | The role to be revoked. |
| `account` | address | The address from which the role will be revoked. |

### Failure scenarios

* The `onlyRole(getRoleAdmin(role))` modifier ensures that the function caller
  has the admin role for the specified role. Only addresses with the admin role
  can revoke roles from other accounts.\
  *"AccessControl: account ", StringsUpgradeable.toHexString(account), " is
  missing role ", StringsUpgradeable.toHexString(uint256(role), 32)*

```solidity Solidity theme={null}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
  _revokeRole(role, account);
}
```

## balanceOf \[read]

Retrieves the balance of tokens owned by a specific account address.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `account` | address | The address for which the token balance is being fetched. |

```solidity Solidity theme={null}
function balanceOf(address account) public view virtual override returns (uint256) {
  return _balances[account];
}
```

## allowance \[read]

Returns the maximum amount the spender is approved to withdraw from the owner's
account. This function retrieves the allowance granted by the owner account
address to the spender account address.

### Parameters

| Parameter | Type | Description |
| :- | :- | :- |
| `owner` | address | The address that granted the allowance. |
| `spender` | address | The address for which the allowance is being fetched. |

```solidity Solidity theme={null}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
  return _allowances[owner][spender];
}

```
