USDCx Support for Wallets¶
Overview¶
Circle and Digital Asset have partnered to develop and implement a USDC token on Canton Network. This implementation requires users to send USDC on L1 chains (starting with Ethereum) to Circle’s xReserve contract which is then created as a USDC token on Canton Network. Conversely a withdrawal request for a USDC token on the Canton Network will result in the release of the asset on another chain. During the existence of the USDC token on Canton Network, it is available for use in financial transactions.
USDC on Canton Network represents USDC locked by Circle on the original L1 chain. And this token on Canton Network, is in the form of a Canton Network Standard Token (CIP-56) as defined through the Canton Network Utilities service.
Wallet providers and exchanges have three options for supporting USDCx on the Canton Network:
Transfer & hold USDCx - Since USDCx is a token standard (CIP-56) compliant asset then as such any wallet that supports the token standard will have built in support for transfers and holding.
Support xReserves deposits and withdrawals - Custom API integration is required for wallet providers and exchanges to support xReserve deposits and withdrawals to the utility-bridge daml models to / from their parties using the xReserves UI. Instructions for doing this are included in the section “Supporting xReserve Deposits and Withdrawals” below.
- Integrating the xReserve UI (Ethereum) into the wallet - To enable a full end-to-end experience for the user, a wallet can integrate against Ethereum directly for deposits on top of integrating point 2. To provide an example for doing this, the xReserves UI as well as open-sourced example scripts are available for reference. This demonstrates the 2 ethereum transactions that must be submitted to an ethereum node:
approve a USDC spending allowance.
depositToRemote to deposit USDC into the xReserve contract.
Supporting xReserve Deposits and Withdrawals¶
The required dar file can be found here
There are 3 choices (API calls) a wallet will need to implement in order to fully support the xReserve:
Onboarding¶
To use the xReserve a party will first need to onboard to the bridge using the below: Example API call:
{
"CreateCommand": {
"templateId": "#utility-bridge-v0:Utility.Bridge.V0.Agreement.User:BridgeUserAgreementRequest",
"createArguments": {
"crossChainRepresentative": "${ADMIN_PARTY_ID}",
"operator": "${UTILITY_OPERATOR_PARTY_ID}",
"bridgeOperator": "${BRIDGE_OPERATOR_PARTY_ID}",
"user": "${USER_PARTY_ID}",
"instrumentId": {
"admin": "${ADMIN_PARTY_ID}",
"id": "USDCx"
},
"preApproval": false
}
}
}
Mint¶
Once a user deposits USDC into ethereum a DepositAttestation is created on the Canton network. In order for the recipient party to claim those funds they will need to call a choice to mint from the DepositAttestation:
#utility-bridge-v0:Utility.Bridge.V0.Attestation.Deposit:DepositAttestation
Example API call:
{
"commands": [
{
"ExerciseCommand": {
"templateId": "#utility-bridge-v0:Utility.Bridge.V0.Agreement.User:BridgeUserAgreement",
"contractId": "${BRIDGE_USER_AGREEMENT_CONTRACT_ID}",
"choice": "BridgeUserAgreement_Mint",
"choiceArgument": {
"depositAttestationCid": "${DEPOSIT_ATTESTATION_CID}",
"factoryCid": "${FACTORY_CID}",
"contextContractIds": "${CONTEXT_CONTRACT_IDS}"
}
}
}
],
"disclosedContracts": "${DISCLOSED_CONTRACTS}",
}
Withdraw¶
To withdraw from the Canton Network to Ethereum a user must burn the USDC on Canton. Specifying the:
destination domain id: Currently only Ethereum is supported (domain id of 0).
Amount: In Decimal to a max 6 decimal precision.
Destination recipient: a valid Ethereum address.
An optional reference. Empty Text field if not provided.
In addition the wallet will need to provide:
The available Holding contract Ids
A UUID as the requestId
Example API call:
{
"commands": [
{
"ExerciseCommand": {
"templateId": "#utility-bridge-v0:Utility.Bridge.V0.Agreement.User:BridgeUserAgreement",
"contractId": "${BRIDGE_USER_AGREEMENT_CONTRACT_ID}",
"choice": "BridgeUserAgreement_Burn",
"choiceArgument": {
"amount": "${AMOUNT_IN_DECIMAL}",
"destinationDomain": "0",
"destinationRecipient": "${ETHEREUM_ADDRESS}",
"holdingCids": "${HOLDING_CONTRACT_IDS}",
"requestId": "${UUID_REQUEST_ID}",
"reference": "",
"factoryCid": "${FACTORY_CID}",
"contextContractIds": "${CONTEXT_CONTRACT_IDS}"
}
}
}
],
"disclosedContracts": "${DISCLOSED_CONTRACTS}",
}
Extracting Contract IDs and Disclosed Contracts¶
The utilities backend provides a Burn Mint Factory API Endpoint
Endpoint:
${UTILITY_BACKEND_URL}/api/utilities/v0/registry/burn-mint-instruction/v0/burn-mint-factory
Example request body:
{
"instrumentId": {
"admin": "${ADMIN_PARTY_ID}",
"id": "USDCx"
},
"inputHoldingCids": "${HOLDING_CONTRACT_IDS_IF_WITHDRAWING}",
"outputs": [
{
"owner": "${ADMIN_PARTY_ID}",
"amount": "${AMOUNT_IN_DECIMAL}" // For minting, this is the amount to mint. For burning, this is the change amount.
}
]
}
When you call the Burn Mint factory endpoint, the response contains the contract IDs and disclosed contracts you need for both minting and withdrawing.
Note that these values can be cached to reduce api calls as these values change infrequently.
As an example for extracting the required contexts and contracts from the response:
// Assume `response` is the parsed JSON from the API call
const choiceContext = response.httpResponse.body.choiceContext;
// Extract CONTEXT_CONTRACT_IDS
const values = choiceContext.choiceContextData.values;
const contextContractIds = {
instrumentConfigurationCid: values["utility.digitalasset.com/instrument-configuration"].value,
appRewardConfigurationCid: values["utility.digitalasset.com/app-reward-configuration"].value,
featuredAppRightCid: values["utility.digitalasset.com/featured-app-right"].value,
};
// Extract FACTORY_CID
const factoryCid = response.httpResponse.body.factoryId;
// Extract DISCLOSED_CONTRACTS
const disclosedContracts = choiceContext.disclosedContracts;
MainNet Environment Variables¶
Variable |
Value |
|---|---|
UTILITY_BACKEND_URL |
|
ADMIN_PARTY_ID |
decentralized-usdc-interchain-rep::12208115f1e168dd7e792320be9c4ca720c751a02a3053c7606e1c1cd3dad9bf60ef |
UTILITY_OPERATOR_PARTY_ID |
auth0_007c6643538f2eadd3e573dd05b9::12205bcc106efa0eaa7f18dc491e5c6f5fb9b0cc68dc110ae66f4ed6467475d7c78e |
BRIDGE_OPERATOR_PARTY_ID |
Bridge-Operator::1220c8448890a70e65f6906bd48d797ee6551f094e9e6a53e329fd5b2b549334f13f |
TestNet Environment Variables¶
Variable |
Value |
|---|---|
UTILITY_BACKEND_URL |
|
ADMIN_PARTY_ID |
decentralized-usdc-interchain-rep::122049e2af8a725bd19759320fc83c638e7718973eac189d8f201309c512d1ffec61 |
UTILITY_OPERATOR_PARTY_ID |
DigitalAsset-UtilityOperator::12202679f2bbe57d8cba9ef3cee847ac8239df0877105ab1f01a77d47477fdce1204 |
BRIDGE_OPERATOR_PARTY_ID |
Bridge-Operator::12209d011ce250de439fefc35d16d1ab9d56fb99ccb24c18d798efb22352d533bcdb |