Notre avis
Cette compétence permet de transférer des USDC entre différentes blockchains via le protocole CCTP de Circle, en utilisant les contrats wrapper Cashmere.
Points forts
- SDK simplifié pour les transferts cross-chain USDC
- Prise en charge de nombreuses blockchains (EVM, Solana, Aptos, Sui)
- Gestion automatique de l'attestation et du relais côté destinataire
- Documentation claire des domaines et des versions CCTP
Limites
- Ne gère que le brûlage côté source ; le relais est automatisé mais dépend du service Cashmere
- Nécessite une API Gas externe pour les frais
- Les délais d'attestation V1 peuvent être longs sur certaines chaînes
Utilisez cette compétence pour envoyer des USDC d'une chaîne à une autre via Cashmere CCTP, en utilisant le SDK ou des transactions brutes.
Ne l'utilisez pas pour des transferts d'autres tokens, ou si vous avez besoin d'un contrôle total sur le processus de mint côté destination.
Analyse de sécurité
SûrThe skill is purely informational, describing a cross-chain USDC transfer protocol and SDK usage. It does not contain any destructive commands, obfuscated payloads, or instructions to exfiltrate data. The use of environment variables for private keys is a standard practice and not a security concern for a listed skill.
Aucun point d'attention détecté
Exemples
Send 100 USDC from Ethereum to Arbitrum using Cashmere CCTP.How do I transfer USDC cross-chain using the Cashmere SDK?What is the Circle CCTP domain ID for Solana?Cashmere CCTP Cross-Chain USDC Transfer Skill
Use this skill when the user asks about Cashmere cross-chain USDC transfers, CCTP contract calls, bridging between EVM / Solana / Aptos / Sui, or building transactions against the Cashmere wrapper contracts.
This skill covers source-side burns only (sending USDC cross-chain). Destination-side claim/mint is handled automatically by Cashmere's own relayers -- no user or SDK action is needed after the source transaction confirms.
Security: No private keys, mnemonics, or signer secrets are stored here.
All addresses below are public on-chain data. The Gas API URL is
https://gas.cashmere.exchange (production).
SDK Usage (Programmatic)
This skill is bundled with @cashmerelabs/cashmere-agent-sdk. If available, prefer calling
the SDK directly instead of building raw transactions:
import { CashmereCCTP } from '@cashmerelabs/cashmere-agent-sdk';
const cctp = new CashmereCCTP({
evm: { privateKey: process.env.EVM_PRIVATE_KEY },
solana: { privateKey: process.env.SOLANA_PRIVATE_KEY },
aptos: { privateKey: process.env.APTOS_PRIVATE_KEY },
sui: { privateKey: process.env.SUI_PRIVATE_KEY },
});
const result = await cctp.transfer({
from: 'ethereum',
to: 'arbitrum',
amount: '100',
recipient: '0xDestinationAddress',
version: 'v2-fast',
feeMode: 'native',
});
// result.txHash, result.explorerUrl
Install: npm install @cashmerelabs/cashmere-agent-sdk
Architecture Overview
Every chain follows the same pattern:
User/Agent ──► Gas API (fee quote + signature)
──► Cashmere Wrapper Contract (verify sig, collect fees)
──► Circle CCTP depositForBurn / depositForBurnWithHook
──► Circle attestation (off-chain)
──► Cashmere relayers auto-mint on destination
1. Circle CCTP Domain IDs
| Domain | Chain | Native | Notes | |--------|---------------|--------|--------------------------------| | 0 | Ethereum | ETH | | | 1 | Avalanche | AVAX | | | 2 | Optimism | ETH | | | 3 | Arbitrum | ETH | | | 5 | Solana | SOL | | | 6 | Base | ETH | | | 7 | Polygon | POL | | | 8 | Sui | SUI | | | 9 | Aptos | APT | | | 10 | Unichain | ETH | | | 11 | Linea | ETH | | | 13 | Sonic | S | | | 14 | Worldchain | ETH | | | 15 | Monad | MON | | | 16 | Sei | SEI | | | 19 | HyperEVM | HYPE | Same domain as Hyperliquid Core|
2. CCTP Versions, Durations, and Fee Structures
V1 (Legacy Attestation-Based)
Requires Circle attestation before destination mint. Supported on EVM <-> EVM (older chains), EVM <-> Solana, EVM <-> Aptos, EVM <-> Sui, Aptos <-> Solana, Aptos <-> Sui, Sui <-> Solana.
Not supported on: Linea, Worldchain, Sei, Sonic, HyperEVM, Monad (V2-only chains).
| Source Chain | Estimated Duration | |---------------|--------------------| | Ethereum | ~15 minutes | | Arbitrum | ~15 minutes | | Base | ~15 minutes | | Optimism | ~15 minutes | | Unichain | ~15 minutes | | Polygon | ~2 minutes | | Avalanche | ~8 seconds | | Solana | ~25 seconds | | Sui | ~8 seconds | | Aptos | ~8 seconds |
Circle burn fee: 0 BPS (no Circle burn fee on V1).
V2 Fast (Threshold 1000)
Attestation-free fast finality. Supported on EVM <-> EVM and EVM <-> Solana only.
| Source Chain | Estimated Duration | |---------------|--------------------| | Ethereum | ~15 seconds | | Arbitrum | ~15 seconds | | Base | ~15 seconds | | Optimism | ~15 seconds | | Unichain | ~15 seconds | | Worldchain | ~15 seconds | | Linea | ~15 seconds | | Polygon | ~8 seconds | | Avalanche | ~8 seconds | | Sonic | ~8 seconds | | Monad | ~8 seconds | | HyperEVM | ~5 seconds | | Sei | ~5 seconds | | Solana | ~15 seconds |
Circle burn fee: Variable BPS from Circle Iris API. Fetched per route.
minFinalityThreshold = 1000.
Not supported from: Avalanche, Sei, Sonic, Polygon, Solana, HyperEVM, Monad (these only support V2 Norm, not V2 Fast).
V2 Norm (Threshold 2000)
Standard finality V2. Supported on all EVM <-> EVM and EVM <-> Solana routes.
| Source Chain | Estimated Duration | |---------------|--------------------| | Ethereum | ~15 minutes | | Arbitrum | ~15 minutes | | Base | ~15 minutes | | Optimism | ~15 minutes | | Unichain | ~15 minutes | | Worldchain | ~15 minutes | | Linea | ~24 hours | | Polygon | ~8 seconds | | Avalanche | ~8 seconds | | Sonic | ~8 seconds | | Monad | ~8 seconds | | HyperEVM | ~5 seconds | | Sei | ~5 seconds | | Solana | ~25 seconds |
Circle burn fee: Variable BPS from Circle Iris API (typically lower than
V2 Fast). minFinalityThreshold = 2000.
Fee Calculation Summary
Cashmere protocol fee (all chains, all versions):
total_fee = (amount * fee_bp / 10000) + static_fee
fee_bp: On-chain basis points, max 100 (1%).static_fee: From the Gas API quote.- Native mode (
isNative=true): static fee paid in native token (ETH/SOL/APT/SUI/etc.), USDC formula usesstatic_fee=0. - Stable mode (
isNative=false): static fee added to USDC deduction.
- Native mode (
- Gas drop: Currently disabled. Pass
gasDropAmount=0in all transfers.
Circle V2 burn fee (maxFee passed on-chain):
bpsTenths = ceil(minimumFee_from_iris * 10)
maxFee = ceil(amount * bpsTenths / 100000)
Where minimumFee comes from Circle Iris API (can be fractional BPS like 1.3).
3. Contract Addresses
EVM — CashmereCCTP Wrapper
| Chain | CashmereCCTP Address |
|------------|----------------------------------------------|
| Ethereum | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Avalanche | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Polygon | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Arbitrum | 0x3412ef459221d1581a08dcD56Ee55B8FaeBf5eEA |
| Optimism | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Base | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Unichain | 0xd002a7172Ac6f90657FCb918B3f7e36372a4bA80 |
| Linea | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Worldchain | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Sei | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| Sonic | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
| HyperEVM | 0x15b2810232ec96ff083ca6d8b785cb930d241d83 |
| Monad | 0xD156fFB54871F4562744d6Be5d6321B5BffCa3B6 |
Solana — Anchor Program
| Item | Address / Key |
|-----------------------------------|------------------------------------------------------|
| Cashmere CCTP Program | 5RsvKL6LFq6yEFiAXEwgYHAN3aLFypeB4AaafdeDnHqM |
| Address Lookup Table | 865YCTTsymGpBjLMTvjd3T3RCGT8yvxnAHhyKZqRFfLi |
| Circle Message Transmitter V1 | CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd |
| Circle Token Messenger Minter V1 | CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3 |
| Circle Message Transmitter V2 | CCTPV2Sm4AdWt5296sk4P66VBZ7bEhcARwFaaS9YPbeC |
| Circle Token Messenger Minter V2 | CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe |
| USDC Mint | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
PDAs:
- Config:
seeds = ["config"]under Cashmere program - Custodian:
seeds = ["emitter"]under Cashmere program - Custody ATA:
seeds = ["__custody"](transient, closed after burn)
Aptos — Move Module
| Item | Address |
|---------------------|----------------------------------------------------------------------|
| Transfer Module | 0xe49afb1896889e3e1dd7bcbb9e31d1df8221899d3d368e98588ac6b4d84b136d |
| Entry Function | {module}::transfer::transfer_outer |
| USDC Coin Type | 0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b |
Sui — Move Package
| Item | Address / Object ID |
|-------------------------------|--------------------------------------------------------------------------|
| Cashmere Transfer Package | 0xdf37112aacb7d3535f7b3b754b9a7b9fa1a6b3a756288dc734522c603c6f11a4 |
| Cashmere Config (shared) | 0x5f1b2e205777713f44a99894d98e1e66e33dc11ff88e50108c94ee79b7ea3d67 |
| Circle TokenMessengerMinter | 0x2aa6c5d56376c371f88a6cc42e852824994993cb9bab8d3e6450cbe3cb32b94e |
| Message Transmitter State | 0xf68268c3d9b1df3215f2439400c1c4ea08ac4ef4bb7d6f3ca6a2a239e17510af |
| TokenMessengerMinter State | 0x45993eecc0382f37419864992c12faee2238f5cfe22b98ad3bf455baf65c8a2f |
| USDC Treasury | 0x57d6725e7a8b49a7b2a612f6bd66ab5f39fc95332ca48be421c3229d514a6de7 |
| DenyList | 0x403 |
| USDC Type | 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC |
USDC Addresses (per chain)
| Chain | USDC Address |
|------------|-----------------------------------------------------|
| Ethereum | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |
| Avalanche | 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E |
| Polygon | 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 |
| Arbitrum | 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 |
| Optimism | 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85 |
| Base | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| Unichain | 0x078D782b760474a361dDA0AF3839290b0EF57AD6 |
| Linea | 0x176211869cA2b568f2A7D4EE941E073a821EE1ff |
| Worldchain | 0x79A02482A880bCe3F13E09da970dC34dB4cD24D1 |
| Sei | 0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392 |
| Sonic | 0x29219dd400f2Bf60E5a23d13Be72B486D4038894 |
| HyperEVM | 0xb88339CB7199b77E23DB6E890353E22632Ba630f |
| Monad | 0x754704Bc059F8C67012fEd69BC8A327a5aafb603 |
| Solana | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| Aptos | 0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b |
| Sui | 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC |
4. Gas API — Fee Quotes and Signatures
Base URL: https://gas.cashmere.exchange
ECDSA Signature (EVM chains)
GET /getEcdsaSig_native?localDomain={domain}&destinationDomain={domain}&isNative={true|false}&isV2={true|false}
Response:
{
"fee": "128000",
"deadline": "1713400000",
"signature": "0x...",
"cctpVersion": "1"
}
Frontend converts: fee = BigInt(fee), deadline = BigInt(deadline),
signature used as-is (hex string).
Ed25519 Signature (Solana, Aptos, Sui)
GET /getEd25519Sig_native?localDomain={domain}&destinationDomain={domain}&isNative={true|false}&version={1|2}
Response:
{
"signature": "0x...",
"message": "0x...",
"publicKey": "0x...",
"destinationDomain": "3",
"fee": "128000",
"deadline": "1713400000"
}
Frontend converts hex strings to Buffer: Buffer.from(sig.slice(2), 'hex').
Circle V2 Burn Fee (via Netlify proxy to Iris)
GET /.netlify/functions/get-burn-fees?localDomain={d}&destinationDomain={d}&threshold={1000|2000}
Proxies to: https://iris-api.circle.com/v2/burn/USDC/fees/{localDomain}/{destinationDomain}
Response:
{
"finalityThreshold": 1000,
"minimumFee": 1.3
}
minimumFee is in BPS (can be fractional).
5. EVM Transfer Pattern
ABI Functions
// V1
function transfer(TransferParams memory _params) external payable;
function transferWithPermit(TransferParams memory _params, PermitParams memory _permitParams) external payable;
// V2
function transferV2(TransferV2Params memory _params) external payable;
function transferV2WithPermit(TransferV2Params memory _params, PermitParams memory _permitParams) external payable;
TransferParams (V1)
struct TransferParams {
uint64 amount; // USDC amount in 6-decimal units
uint128 fee; // Static fee from Gas API
uint64 deadline; // Unix timestamp
uint128 gasDropAmount; // Pass 0 (gas drop currently disabled)
uint32 destinationDomain; // Circle CCTP domain
bytes32 recipient; // 32-byte padded destination address
bytes32 solanaOwner; // Solana wallet owner (0x0 if not Solana dest)
bool isNative; // true = fees in native token
bytes signature; // ECDSA from Gas API
}
TransferV2Params
Same as V1 plus:
uint256 maxFee; // Calculated from Circle Iris minimumFee
uint32 minFinalityThreshold; // 1000 (fast) or 2000 (norm)
bytes hookData; // Always "0x00" for standard transfers
PermitParams (for WithPermit variants)
struct PermitParams {
uint256 value; // USDC amount to permit
uint256 deadline; // Permit deadline (transfer deadline + 6000)
bytes signature; // EIP-2612 permit signature
}
TypeScript Example (viem)
import { writeContract, simulateContract } from '@wagmi/core';
const GAS_API = 'https://gas.cashmere.exchange';
async function evmCctpTransfer(
srcChain: string, // e.g. 'ethereum'
srcDomain: number, // e.g. 0
dstDomain: number, // e.g. 3 (arbitrum)
amount: bigint, // USDC in 6 decimals, e.g. 100_000_000n for 100 USDC
recipientBytes32: `0x${string}`,
isNative: boolean,
isV2: boolean,
) {
// 1. Get fee quote + signature from Gas API
const sigResp = await fetch(
`${GAS_API}/getEcdsaSig_native?localDomain=${srcDomain}&destinationDomain=${dstDomain}&isNative=${isNative}&isV2=${isV2}`
).then(r => r.json());
const fee = BigInt(sigResp.fee);
const deadline = BigInt(sigResp.deadline);
const signature = sigResp.signature;
// 2. Calculate msg.value (native fee only when isNative=true)
const value = isNative ? fee : 0n;
// 3. Build args
if (!isV2) {
const args = [{
amount,
fee,
deadline,
gasDropAmount: 0n, // gas drop currently disabled
destinationDomain: dstDomain,
recipient: recipientBytes32,
solanaOwner: '0x' + '0'.repeat(64),
isNative,
signature,
}];
// Simulate then send
await simulateContract(config, {
address: CASHMERE_CCTP_ADDRESS, // per chain
abi: cashmereCctpAbi,
functionName: 'transfer', // or 'transferWithPermit'
args,
value,
});
return writeContract(config, { /* same params */ });
} else {
// V2: fetch burn fee from Circle Iris
const burnFee = await fetch(
`/.netlify/functions/get-burn-fees?localDomain=${srcDomain}&destinationDomain=${dstDomain}&threshold=1000`
).then(r => r.json());
const bpsTenths = Math.ceil((burnFee.minimumFee ?? 100) * 10);
const maxFee = (amount * BigInt(bpsTenths) + 99999n) / 100000n;
const args = [{
amount,
maxFee,
fee,
deadline,
gasDropAmount: 0n, // gas drop currently disabled
destinationDomain: dstDomain,
minFinalityThreshold: 1000, // or 2000 for norm
recipient: recipientBytes32,
solanaOwner: '0x' + '0'.repeat(64),
isNative,
hookData: '0x00',
signature,
}];
// Simulate then send (transferV2 or transferV2WithPermit)
}
}
On-Chain Signature Verification (EVM)
The contract verifies ecrecover on:
keccak256(abi.encodePacked(
localDomain, // uint32
destinationDomain, // uint32
fee, // uint128
deadline, // uint64
isNative, // bool
uint8(1) // version: 1 for V1, 2 for V2
))
6. Solana Transfer Pattern
Instructions (Anchor IDL)
transfer(V1):usdc_amount,destination_domain,recipient: [u8;32],solana_owner: [u8;32],fee,deadline,gas_drop_amount(pass 0),fee_is_nativetransfer_v2: Same as above plusmax_fee,min_finality_threshold
Transaction Structure
A Solana CCTP transfer is a VersionedTransaction with these instructions:
ComputeBudgetProgram.setComputeUnitLimit({ units: 160_000 })Ed25519Program.createInstructionWithPublicKey({ publicKey, message, signature })— from Gas API responseprogram.methods.transfer(...)orprogram.methods.transferV2(...)— Anchor instruction
Signed by: wallet first (allows Phantom Lighthouse), then cctpMessageSigner keypair.
Uses Address Lookup Table 865YCTTsymGpBjLMTvjd3T3RCGT8yvxnAHhyKZqRFfLi for compressed V0 messages.
Key Accounts
{
ownerTokenAccount: userUsdcAta,
feeCollectorSolAccount: config.feeCollectorSol,
feeCollectorUsdcAccount: config.feeCollectorUsdc,
gasDropCollectorSolAccount: config.gasDropCollectorSol, // still required by IDL
gasDropCollectorUsdcAccount: config.gasDropCollectorUsdc, // still required by IDL
owner: walletPublicKey,
remoteTokenMessenger: PDA("remote_token_messenger", [destDomain.toString()]),
burnSource: userUsdcAta,
messageSentEventData: cctpMessageSigner.publicKey, // new Keypair per tx
// V2 only:
tokenMessengerMinterProgram: TOKEN_MESSENGER_MINTER_V2_PROGRAM_ID,
messageTransmitterProgram: MESSAGE_TRANSMITTER_V2_PROGRAM_ID,
}
TypeScript Example
import { Program } from '@coral-xyz/anchor';
import { Ed25519Program, Keypair, PublicKey, VersionedTransaction, TransactionMessage, ComputeBudgetProgram } from '@solana/web3.js';
const GAS_API = 'https://gas.cashmere.exchange';
const PROGRAM_ID = new PublicKey('5RsvKL6LFq6yEFiAXEwgYHAN3aLFypeB4AaafdeDnHqM');
async function solanaCctpTransfer(
connection: Connection,
wallet: WalletAdapter,
amount: bigint,
destDomain: number,
recipientBytes32: number[],
isNative: boolean,
isV2: boolean,
) {
// 1. Get Ed25519 signature from Gas API
const sigResp = await fetch(
`${GAS_API}/getEd25519Sig_native?localDomain=5&destinationDomain=${destDomain}&isNative=${isNative}&version=${isV2 ? 2 : 1}`
).then(r => r.json());
const signature = Buffer.from(sigResp.signature.slice(2), 'hex');
const message = Buffer.from(sigResp.message.slice(2), 'hex');
const publicKey = Buffer.from(sigResp.publicKey.slice(2), 'hex');
// 2. Build Ed25519 verify instruction
const signatureIx = Ed25519Program.createInstructionWithPublicKey({
publicKey, message, signature
});
// 3. Build Anchor transfer instruction
const cctpMessageSigner = new Keypair();
const transferIx = await program.methods
.transfer(
new BN(amount.toString()),
sigResp.destinationDomain,
recipientBytes32,
solanaOwnerBytes32,
new BN(sigResp.fee),
new BN(sigResp.deadline),
new BN(0), // gas drop disabled
isNative,
)
.accounts({ /* see Key Accounts above */ })
.instruction();
// 4. Assemble and sign
const computeIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 160_000 });
const lookupTable = await connection.getAddressLookupTable(ALT_ADDRESS);
const tx = new VersionedTransaction(
new TransactionMessage({
recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
payerKey: wallet.publicKey,
instructions: [computeIx, signatureIx, transferIx],
}).compileToV0Message([lookupTable.value])
);
tx = await wallet.signTransaction(tx);
tx.sign([cctpMessageSigner]);
return connection.sendTransaction(tx);
}
7. Aptos Transfer Pattern
Entry Function
{MODULE_ADDR}::transfer::transfer_outer
Where MODULE_ADDR = 0xe49afb1896889e3e1dd7bcbb9e31d1df8221899d3d368e98588ac6b4d84b136d
Arguments (positional)
| Index | Type | Description | |-------|------------|-------------------------------------------------| | 0 | u64 | USDC amount (6 decimals) | | 1 | u64 | Native fee amount (0 if stable mode) | | 2 | u32 | Destination domain | | 3 | address | Recipient (bytes32 hex) | | 4 | address | Solana owner (0x0 if not Solana destination) | | 5 | u64 | Static fee from Gas API | | 6 | u64 | Deadline from Gas API | | 7 | u64 | Gas drop amount (pass 0, currently disabled) | | 8 | bool | isNative | | 9 | vector<u8> | Ed25519 signature bytes |
TypeScript Example
import { InputEntryFunctionData } from '@aptos-labs/ts-sdk';
const GAS_API = 'https://gas.cashmere.exchange';
const MODULE = '0xe49afb1896889e3e1dd7bcbb9e31d1df8221899d3d368e98588ac6b4d84b136d';
async function aptosCctpTransfer(
aptosClient: AptosClient,
senderAddress: string,
amount: bigint,
destDomain: number,
recipientBytes32: string,
isNative: boolean,
) {
// 1. Get Ed25519 signature from Gas API (domain 9 = Aptos)
const sigResp = await fetch(
`${GAS_API}/getEd25519Sig_native?localDomain=9&destinationDomain=${destDomain}&isNative=${isNative}`
).then(r => r.json());
const signature = Buffer.from(sigResp.signature.slice(2), 'hex');
const fee = sigResp.fee;
const deadline = sigResp.deadline;
// 2. Build transaction
const txData: InputEntryFunctionData = {
function: `${MODULE}::transfer::transfer_outer`,
typeArguments: [],
functionArguments: [
amount.toString(),
isNative ? BigInt(fee).toString() : '0', // native fee amount
destDomain,
recipientBytes32,
'0x' + '0'.repeat(64), // solanaOwner
fee,
deadline,
'0', // gas drop disabled
isNative,
Array.from(signature), // Pontem: Array, others: Uint8Array
],
};
// 3. Simulate and submit
const transaction = await aptosClient.transaction.build.simple({
sender: senderAddress,
data: txData,
});
// Sign and submit via wallet adapter
}
Note: Pontem wallet requires Array.from(signature) format; other wallets
(Petra, Nightly) accept Uint8Array directly.
8. Sui Transfer Pattern
Three-Step PTB (Programmable Transaction Block)
Sui uses a single atomic PTB with three moveCall steps:
Step 1: Cashmere prepare
target: {package}::transfer::prepare_deposit_for_burn_ticket
typeArguments: [USDC_TYPE]
arguments: [usdcCoin, nativeFeeCoin, destDomain, recipient, solanaOwner,
fee, deadline, gasDropAmount (pass 0), isNative, signatureVector,
configObject, clockObject]
returns: [ticket, depositInfo]
Step 2: Circle deposit
target: {tokenMessengerMinter}::deposit_for_burn::deposit_for_burn_with_package_auth
typeArguments: [USDC_TYPE, AUTH_STRUCT]
arguments: [ticket, tmmState, mtState, denyList, usdcTreasury]
returns: [burnMessage, message]
Step 3: Cashmere finalize
target: {package}::transfer::post_deposit_for_burn
arguments: [burnMessage, message, depositInfo, configObject]
TypeScript Example
import { Transaction, coinWithBalance } from '@mysten/sui/transactions';
import { SUI_CLOCK_OBJECT_ID } from '@mysten/sui/utils';
const GAS_API = 'https://gas.cashmere.exchange';
const CASHMERE_PKG = '0xdf37112aacb7d3535f7b3b754b9a7b9fa1a6b3a756288dc734522c603c6f11a4';
const CASHMERE_CONFIG = '0x5f1b2e205777713f44a99894d98e1e66e33dc11ff88e50108c94ee79b7ea3d67';
const TMM_PKG = '0x2aa6c5d56376c371f88a6cc42e852824994993cb9bab8d3e6450cbe3cb32b94e';
const MT_STATE = '0xf68268c3d9b1df3215f2439400c1c4ea08ac4ef4bb7d6f3ca6a2a239e17510af';
const TMM_STATE = '0x45993eecc0382f37419864992c12faee2238f5cfe22b98ad3bf455baf65c8a2f';
const USDC_TREASURY = '0x57d6725e7a8b49a7b2a612f6bd66ab5f39fc95332ca48be421c3229d514a6de7';
const USDC_TYPE = '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC';
async function suiCctpTransfer(
suiClient: SuiClient,
senderAddress: string,
amount: bigint,
destDomain: number,
recipientBytes32: string,
isNative: boolean,
) {
// 1. Get Ed25519 signature from Gas API (domain 8 = Sui)
const sigResp = await fetch(
`${GAS_API}/getEd25519Sig_native?localDomain=8&destinationDomain=${destDomain}&isNative=${isNative}`
).then(r => r.json());
const signature = Buffer.from(sigResp.signature.slice(2), 'hex');
// 2. Build PTB
const tx = new Transaction();
const usdcCoin = coinWithBalance({
type: USDC_TYPE,
balance: amount,
});
const nativeCoin = tx.splitCoins(tx.gas, [
tx.pure.u64(isNative ? BigInt(sigResp.fee).toString() : '0')
]);
// Step 1: prepare
const [ticket, depositInfo] = tx.moveCall({
target: `${CASHMERE_PKG}::transfer::prepare_deposit_for_burn_ticket`,
typeArguments: [USDC_TYPE],
arguments: [
usdcCoin, nativeCoin,
tx.pure.u32(destDomain),
tx.pure.address(recipientBytes32),
tx.pure.address('0x' + '0'.repeat(64)),
tx.pure.u64(sigResp.fee),
tx.pure.u64(sigResp.deadline),
tx.pure.u64('0'), // gas drop disabled
tx.pure.bool(isNative),
tx.pure.vector('u8', Array.from(signature)),
tx.object(CASHMERE_CONFIG),
tx.object(SUI_CLOCK_OBJECT_ID),
],
});
// Step 2: Circle burn
const [burnMessage, message] = tx.moveCall({
target: `${TMM_PKG}::deposit_for_burn::deposit_for_burn_with_package_auth`,
typeArguments: [USDC_TYPE, `${CASHMERE_PKG}::transfer::Auth`],
arguments: [
ticket,
tx.object(TMM_STATE),
tx.object(MT_STATE),
tx.object('0x403'),
tx.object(USDC_TREASURY),
],
});
// Step 3: finalize
tx.moveCall({
target: `${CASHMERE_PKG}::transfer::post_deposit_for_burn`,
arguments: [burnMessage, message, depositInfo, tx.object(CASHMERE_CONFIG)],
});
tx.setSenderIfNotSet(senderAddress);
// 3. Sign and execute via wallet
return suiSignAndExecuteTransaction({ transaction: tx });
}
9. Recipient Address Encoding
All chains encode the destination address as bytes32:
- EVM -> EVM: Left-pad 20-byte address to 32 bytes.
- Any -> Solana: Compute the recipient's USDC Associated Token Account
(ATA) and encode as bytes32. Also pass
solanaOwneras the wallet pubkey in bytes32. UsegetAssociatedTokenAddressSync(USDC_MINT, walletPubkey). - Any -> Aptos/Sui: The address is already 32 bytes.
- Solana owner field: Set to
0x0...0(64 hex zeros) when destination is not Solana.
10. Version Routing Rules — Per Chain
Source Chain Capabilities
Which CCTP versions each chain can send from:
| Source Chain | V1 (0 BPS) | V2 Fast (1000) | V2 Norm (2000) | Possible Destinations | |--------------|------------|----------------|----------------|-------------------------------------------------| | Ethereum | Y | Y | Y | All EVM, Solana, Aptos, Sui | | Arbitrum | Y | Y | Y | All EVM, Solana, Aptos, Sui | | Base | Y | Y | Y | All EVM, Solana, Aptos, Sui | | Optimism | Y | Y | Y | All EVM, Solana, Aptos, Sui | | Unichain | Y | Y | Y | All EVM, Solana, Aptos, Sui | | Polygon | Y | N | Y | All EVM, Solana, Aptos, Sui | | Avalanche | Y | N | Y | All EVM, Solana, Aptos, Sui | | Linea | N | Y | Y | All EVM, Solana only (V2-only chain) | | Worldchain | N | Y | Y | All EVM, Solana only (V2-only chain) | | Sei | N | N | Y | All EVM, Solana only (V2-only, no V2 Fast) | | Sonic | N | N | Y | All EVM, Solana only (V2-only, no V2 Fast) | | HyperEVM | N | N | Y | All EVM, Solana only (V2-only, no V2 Fast) | | Monad | N | N | Y | All EVM, Solana only (V2-only, no V2 Fast) | | Solana | Y | N | Y | All EVM (V1+V2 Norm), Aptos (V1), Sui (V1) | | Aptos | Y | N | N | V1-legacy EVM, Solana, Sui (V1 only) | | Sui | Y | N | N | V1-legacy EVM, Solana, Aptos (V1 only) |
Destination Chain Constraints
Which versions can send to each destination:
| Destination | Can receive V1 | Can receive V2 | Notes | |--------------|---------------|----------------|----------------------------------------------| | Ethereum | Y | Y | | | Arbitrum | Y | Y | | | Base | Y | Y | | | Optimism | Y | Y | | | Unichain | Y | Y | | | Polygon | Y | Y | | | Avalanche | Y | Y | | | Linea | N | Y | V2-only destination | | Worldchain | N | Y | V2-only destination | | Sei | N | Y | V2-only destination | | Sonic | N | Y | V2-only destination | | HyperEVM | N | Y | V2-only destination | | Monad | N | Y | V2-only destination | | Solana | Y | Y | V1 from any; V2 from EVM only | | Aptos | Y | N | V1 only (from V1-legacy EVM, Solana, Sui) | | Sui | Y | N | V1 only (from V1-legacy EVM, Solana, Aptos) |
V1-Unsupported Chains (V2-only)
These chains have no V1 support — neither as source nor destination:
linea, worldchain, sei, sonic, hyperevm, monad, stable, megaeth
V2 Fast-Unsupported Sources
These chains can only send V2 Norm (threshold 2000), not V2 Fast (threshold 1000):
avalanche, sei, sonic, polygon, solana, hyperevm, monad
11. Source Code References
| Area | Path |
|------------|----------------------------------------------------------|
| EVM Contract | evm/src/CashmereCCTP.sol |
| Solana Program | sol/programs/cashmere_cctp/src/ |
| Solana IDL | sol/target/idl/cashmere_cctp.json |
| Aptos Module | aptos/build/cashmere_cctp/sources/transfer.move |
| Sui Module | sui/sources/transfer.move |
Expert Next.js App Router
Developpement
Un skill qui transforme Claude en expert Next.js App Router.
Générateur de README
Developpement
Crée des README.md professionnels et complets pour vos projets.
Rédacteur de Documentation API
Developpement
Génère de la documentation API complète au format OpenAPI/Swagger.