Gateway Wallet contracts
The wallet contract accepts deposits from users via direct transfer, EIP-2612 permit, or ERC-3009 authorization. It’s deployed to multiple chains so users can deposit from whatever source chain they hold USDC on. The contract is non-custodial, meaning users always have full control over their USDC and Circle can’t transfer or burn any USDC without explicit user authorization. Once USDC is deposited and the deposit events are finalized onchain, the USDC can be used crosschain. To preserve the non-custodial nature of the USDC held in the Gateway Wallet contract, there is a trustless withdrawal mechanism that may be used in the unlikely event that Circle’s APIs are down for an extended period or service is otherwise unavailable. To withdraw USDC onchain with no API interaction, users must first initiate a withdrawal with a transaction, wait for a 7-day withdrawal delay period, and then the user may complete the withdrawal and receive the USDC. This delay is what allows the Gateway System to safely issue attestations to instantly transfer USDC to other chains, since it guarantees that there is sufficient time to submit the corresponding burn transaction.Gateway Minter contracts
The minter contract accepts attestations signed by the Gateway System and mints USDC to the specified destination. It’s also deployed to multiple chains, including chains that may not yet support the wallet contract.Gateway system
Circle runs an offchain, automated system that serves an API for user interaction, observes onchain events, and ensures that every mint on a destination chain corresponds 1:1 with a burn on each source chain.Balances
At the center of the system is an offchain ledger that represents the USDC balances that are deposited and are available for use in instant transfers. These balances are tracked for every combination of chain, token, and address. They’re eventually consistent with onchain state, where safety is ensured by mechanisms built into the wallet contract.Inputs
The following table describes the main inputs to the Gateway System, along with what it does in response to each.
All onchain events are only observed as they’re finalized. See
Required block confirmations
for the details on finality on each supported chain.
Core primitives
The contracts and API share a set of primitives that are used to represent transfers consistently, both when interacting with the API and as inputs to the smart contracts. There is also a byte encoding for each that’s used across chains. See the source code of the EVM contracts for details about widths, offsets, and type markers.Solana uses different message encodings and signing requirements to accommodate
transaction size limits. See
Solana programs and interfaces for
Solana-specific details.
Transfer specification
A transfer specification describes everything about a transfer from one domain to another. It’s embedded in the other two primitives, and itskeccak256 hash is used as a crosschain
identifier and replay protection.
TransferSpec
Burn intent
A burn intent is constructed and signed by the user, and provided to the Gateway API during a transfer request. This is used to authenticate the user (since it must be signed by the address specified in thesourceSigner field of the transfer spec) as
well as to declare the parameters of the desired transfer.
BurnIntent
Note: When Arbitrum is the source chain, the
maxBlockHeight in the burn
intent should be in terms of the Ethereum L1 block height. Refer to the
Arbitrum
Docs
to learn more about Arbitrum’s behavior around block height.Note: When Solana is the source chain,
maxBlockHeight refers to the last
slot before the signed message is invalid.withdrawalDelay from the current block), and that the fee
is sufficient to cover both the gas for the burn transaction and the transfer
fee.
If multiple burn intents share a common sourceSigner and the relevant chains
all share the same signature scheme (such as multiple EVM chains), burn intents
may be packed together into a burn intent set and signed as a single payload:
BurnIntentSet
Note: You can include a maximum of 16 burn intents in a single transfer
request. The Gateway API returns a
400 error for requests that include more
than 16 burn intents.Note: Burn intent sets are only supported on EVM chains. On Solana, each
transfer must be specified as a separate signed
BurnIntent. See Solana
programs and interfaces for details.Attestation
An attestation is constructed and signed by the Gateway System in response to a transfer request. It proves to the minter contract that at the time of the transfer request, the user had a sufficient balance in the wallet contracts and all other details of the transfer were valid, so the mint is safe to perform. Attestations expire after 10 minutes.Attestation
Note: When Arbitrum is the destination chain, the
maxBlockHeight in the
attestation is returned in terms of the Ethereum L1 block height. Refer to
the Arbitrum
Docs
to learn more about Arbitrum’s behavior around block height.keccak256 hash is emitted during the
mint transaction and the same hash is emitted during the corresponding burn
transaction. This allows for crosschain traceability and reconciles the 1:1
relationship between mints and burns in the system.
When a transfer involves multiple source domains (such as when the user passes a
burn intent set or multiple standalone burn intents), the Gateway System
constructs and signs an attestation set:
AttestationSet
While events are emitted for each attestation contained in a set, the entire
transaction is atomic and only one mint (of the total value of all contained
attestations) happens during the transaction.
Key operations
The Gateway System supports the following key operations.Deposit
To deposit USDC into the Gateway System, users may choose between several onchain deposit methods:
It’s important to note that before deposited USDC shows up in the Gateway System
and may be used for transfers, the deposit transactions must be finalized
onchain. See
Required block confirmations
for more details about what’s considered finalized on each supported chain.
Check balances
Use the/v1/balances endpoint of the API to check the latest available balance
recorded by the Gateway System. These balances are what’s available to be
instantly transferred using a transfer request.
Check pending deposits
Use the/v1/deposits endpoint to
check pending deposits. A deposit is in pending state when the user has
submitted the deposit transaction but it has not yet been processed by the
Gateway service.
Instant transfer
First, construct a burn intent or burn intent set describing the desired transfer. Sign it with the address that owns the USDC or is an authorized delegate (see below for more information about delegates). Pass the burn intents to the/v1/transfer endpoint of the API to request an
attestation from the Gateway System. If the transfer is valid and the request is
not forwarded, the API responds with top-level attestation and signature
fields for the destination domain.
Forwarded requests may omit those fields. To retrieve the richer transfer
record, including burnIntents and nested attestation.payload and
attestation.signature fields, use
GET /v1/transfer/{id}.
Next, make a contract call to the minter contract on the destination chain using
the attestation and signature when mint submission is not being forwarded. To
atomically compose this mint with other onchain actions, use a multi-call
contract.
Note that if destinationCaller is specified in any of the transfer specs, it
must match the sender of the transaction (this can be used to prevent
front-running a mint when it’s intended to be composed with other actions in the
same transaction).
The Gateway System ensures that if an attestation is used, the corresponding
burn transaction is submitted to all involved source chains.
Withdrawal
There are two ways to remove USDC from the Gateway system: instant transfers and trustless withdrawals.Instant
The destination chain of a transfer may be the same as the source chain. This means that to withdraw USDC from the wallet contract on the same chain, the transfer flow described in the preceding section applies. The only fee for same-chain withdrawals is to cover gas for the burn transaction (no other transfer fee is charged). The reason same-chain withdrawals still involve a mint and burn rather than just a transfer out of the wallet contract is to ensure that there are no methods of removing USDC from the wallet contract that don’t involve a user signature.Trustless
In the unlikely event that Circle’s APIs are down for an extended period or service is unavailable for any other reason, users can trustlessly withdraw USDC with a delay. First, make a contract call to theinitiateWithdrawal
method with the desired amount to withdrawal. After a delay of 7 days, make a
contract call to the
withdraw method
to complete the withdrawal.
Delegates
Because the Gateway System needs to statically verify the signature on all burn intents without involving any onchain state and guarantee that the signature is valid at the time of the burn transaction, SCA signatures such as EIP-1271 signatures can’t be accepted. Burn intents must be signed by an EOA. There is a delegate mechanism built into Gateway that allows SCAs to make use of the protocol. Any user can add one or more other addresses that are allowed to sign transfer requests on their behalf. This acts as a full allowance for the deposited USDC. These delegate addresses should be EOAs capable of producing a valid ECDSA signature to be effective. For EOAs that have upgraded to SCAs using EIP-7702, this delegation is unnecessary, since there is still an underlying EOA that can produce the necessary signature directly.Adding a delegate
To add a delegate, use theaddDelegate
method on the wallet contract. This needs to be done for each wallet contract
where the depositor address holds USDC across all chains.
Removing a delegate
To remove a delegate (for key rotation or other purposes), use theremoveDelegate
method of the wallet contract. This needs to be done for each wallet contract
where the depositor address holds USDC across all chains.
Note that when delegates are removed, signatures they produced are still valid
for the purpose of fulfilling burn intents onchain. This ensures that burns may
be executed safely even in the event of a revocation. The API still reflects
revocations as soon as they’re finalized onchain.
Implementation considerations
When building directly with Gateway contracts and APIs, keep these safety checks in your application flow:- Use the Gateway Wallet deposit methods only. Do not expose the Gateway Wallet contract as a generic ERC-20 recipient; standard ERC-20 transfers to the Gateway Wallet contract result in loss of USDC.
- Prefer signature-based or bounded authorization for deposits where possible.
Use
depositWithPermitordepositWithAuthorizationwhen the token and wallet support them. If your flow usesapprovefollowed bydeposit, treat them as two separate transactions and surface their status separately. - Treat pending deposits separately from available balance. Deposits must be finalized and processed by the Gateway System before they can be used for instant transfers.
- Treat delegates as high-privilege signers. A delegate can sign transfer requests for deposited USDC on the wallet contract where it is authorized. Add delegates only where needed, monitor them, and remove them during key rotation or access removal.
- Do not assume delegate removal cancels signed burn intents. Burn intents that were signed before revocation remain valid for onchain execution until they expire.
- Track expiry and transfer records. Burn intents expire according to
maxBlockHeight, and Gateway attestations expire if unused. For forwarded transfers, store the returned transferidand useGET /v1/transfer/{id}to check status. - Use
destinationCallerfor composed mint flows where only a specific caller should be able to use the attestation. This can help prevent third-party mint front-running when the mint is intended to be part of another onchain action. - Include the trustless withdrawal path in recovery planning. If Circle’s APIs are unavailable for an extended period, users can initiate a withdrawal and complete it after the 7-day delay.