> ## 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.

# USDC-backed stablecoin reference specification

This reference spec is for blockchain partners looking to develop and deploy a
USDC-backed stablecoin that integrates with xReserve. It describes the
recommended capabilities your smart contract should have, including the state to
track, the callable functions to expose, and the administrative functions
typically restricted to the contract owner.

This spec is a recommended reference implementation, not a mandatory template.
You should adapt the logic in this spec to your blockchain's smart contract
language and environment, and flag any notable deviations to Circle during
integration so both teams understand them.

<Info>
  View a
  [reference contract](https://github.com/circlefin/evm-xreserve-contracts/blob/master/src/examples/USDCx.sol)
  that mints and burns USDC-backed stablecoins in the
  [Circle xReserve Contracts](https://github.com/circlefin/evm-xreserve-contracts)
  GitHub repository.
</Info>

## Deployment requirements

USDC-backed stablecoins are backed 1:1 by an equivalent amount of USDC held in
Circle's xReserve contract. Your contract mints them after verifying a
[deposit attestation](/xreserve/concepts/technical-guide#deposit-attestation),
and users burn them when they want to withdraw USDC or other USDC-backed
stablecoins on a supported blockchain.

When implementing your USDC-backed stablecoin contract, ensure that you:

* Follow the decimal precision of native USDC, which is 6 decimal places. If
  your blockchain token standard uses a different decimal precision, you must
  handle the decimal conversion in the onchain contract so that it still aligns
  with 6-decimal USDC.
* Use `uint256` for balances and amounts by default. If your runtime forces a
  smaller width such as `uint128` or `uint64`, select the equivalent integer
  type and implement overflow and underflow safeguards for that width.

## State and configuration requirements

The following table lists the variables your token contract should track and the
invariants that must remain true after every call that changes state.

| Variable                                     | Description                                                                                                 | Required Invariant                                                                                                                                  |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uint32 domain`                              | Circle-assigned identifier for your blockchain.                                                             | Value must match the domain ID that Circle assigned to your blockchain. It must be immutable after deployment.                                      |
| `mapping(bytes32 => uint256) balances`       | Tracks balances for each USDC-backed stablecoin account.                                                    | Must be non-negative.                                                                                                                               |
| `mapping(bytes32 => bool) usedNonces`        | Tracks consumed deposit intents (for replay protection).                                                    | Must be `false` before mint and set `true` atomically during mint.                                                                                  |
| `mapping(address => bool) xReserveAttesters` | Allowlist of [xReserve attester](/xreserve/concepts/technical-guide#attesters) addresses (in bytes20 form). | Only the owner can configure this list.                                                                                                             |
| `uint256 minBurnSize`                        | Minimum burn amount for withdrawals.                                                                        | The owner must implement and configure this amount.                                                                                                 |
| `uint256 totalSupply` (optional onchain)     | Aggregate minted minus burned balance.                                                                      | Must equal the sum of all account balances. Can be omitted if the complete USDC-backed token supply is indexed and exposed offchain through an API. |

## Core contract functions

Your USDC-backed stablecoin contract should expose these external functions.

### `mint(bytes depositIntent, bytes depositAttestation, uint256 feeAmount)`

Mints USDC-backed stablecoins after verifying a deposit attestation.

For the canonical `DepositIntent` message format, see the
[Technical guide](/xreserve/concepts/technical-guide#deposit-intent).

**Preconditions**

The following conditions must be met before you move state or the call will
revert:

* `ECDSA.recover(hash(payload), signature)` must resolve to an address whose
  `bytes20` is `true` in the `xReserveAttesters` allowlist.
* `depositIntent.magic` must be `0x5a2e0acd`.
* `depositIntent.version` must be `1`.
* `depositIntent.amount` must be greater than zero.
* `depositIntent.remoteDomain` must match this USDC-backed stablecoin contract's
  `domain`.
* `depositIntent.remoteToken` must match the identifier for this USDC-backed
  stablecoin contract.
* `depositIntent.localToken` and `depositIntent.localDepositor` must not be zero
  addresses.
* `depositIntent.amount` must be at least `depositIntent.maxFee`.
* `depositIntent.maxFee` must be greater than or equal to the `feeAmount` passed
  in.
* `usedNonces[depositIntent.nonce]` must be `false`.

**State transitions**

When all preconditions are met, state must be updated in this order:

1. Set `usedNonces[depositIntent.nonce]` = `true`.
2. Add `depositIntent.amount - feeAmount` to the recipient's balance.
3. Add `feeAmount` to the relayer's balance if a relayer is present.
4. Increase `totalSupply` by `depositIntent.amount`.

**Postconditions**

After the mint completes, make sure:

* `totalSupply` equals exactly the previous supply + `depositIntent.amount`.
* The sum of balances increased by exactly `depositIntent.amount`.
* Your contract emits a mint event:
  `mint(recipient, relayer, amount, feeAmount, remoteDomain, remoteToken)`.

### `burn(uint256 amount, uint32 destinationDomain, bytes32 destinationRecipient)`

Burns USDC-backed stablecoins so xReserve can release USDC on the destination.

<Tip>
  **Recommendation**: Keep this signature where possible. Using the same parameter
  order and types simplifies downstream integrations that expect this interface.
</Tip>

For information on withdrawals, burn intents, and burn intent signatures, see
the [Technical guide](/xreserve/concepts/technical-guide#withdrawals).

**Preconditions:**

The following conditions must be met before you move state or the call will
revert:

* `amount` must be greater than zero.
* The caller (`msg.sender`) must hold at least `amount`.
* `amount` must meet or exceed `minBurnSize`.

**State transitions:**

When all preconditions are met, state must be updated in this order:

1. Decrement the caller's balance by `amount`.
2. Decrement `totalSupply` by `amount`.

**Postconditions**

After the mint completes, make sure:

* Your contract emits a burn event:
  `burn(depositor, domain, amount, destinationDomain, destinationRecipient)`.

## Administrative functions

Access to these administrative functions should be restricted to the contract
owner or an equivalent privileged role controlled by your blockchain team.

### `setAttester(bytes32 attester, bool enabled)`

Enables or disables an attester address in the allowlist. Set `enabled` to
`true` to approve an
[xReserve attester](/xreserve/concepts/technical-guide#attesters). Configure
more than one approved attester so xReserve can rotate attester keys without
downtime.

### `setMinBurnSize(uint256 minBurnSize)`

Specifies the minimum amount to burn.
