Circle USYC 백서

Circle USYC

원문

bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 75쪽 중 36쪽

quickstart](cctp/quickstarts/transfer-usdc-ethereum-to-arc). <Note> Fast Transfers from Ethereum to HyperEVM incur a protocol fee and a dynamic forwarding fee for the HyperEVM chain relay transaction. Fast Transfer is the default for transfers from Ethereum to HyperCore. </Note> ## Steps Use the following steps to transfer USDC from Ethereum to HyperCore. ### Step 1. Get CCTP fees from the API Query the CCTP API for the fees for transferring USDC from Ethereum to HyperCore. This value is passed to the `maxFee` parameter in the `depositForBurnWithHook` transaction. The following is an example request to the CCTP using source domain 0 (Ethereum) and destination domain 19 (HyperEVM): ```shell theme={null} curl --request GET \ --url 'https://iris-api-sandbox.circle.com/v2/burn/USDC/fees/0/19?forward=true&hyperCoreDeposit=true' \ --header 'Content-Type: application/json' ``` **Response:** ```json theme={null} [ { "finalityThreshold": 1000, // fast transfer "minimumFee": 1, // in basis points "forwardFee": { "low": 211203, "med": 216109, // 0.216109 USDC "high": 221014 } }, { "finalityThreshold": 2000, // standard transfer "minimumFee": 0, "forwardFee": { "low": 211203, "med": 216109, // 0.216109 USDC "high": 221014 } } ] ``` ### Step 2. Calculate the USDC amounts minus fees There is a protocol fee to deposit USDC from Ethereum to HyperEVM and a dynamic forwarding fee for the HyperEVM chain relay transaction. The CCTP fast transfer fee is 1 basis point (0.01%) of the transfer amount. The forwarding fee is 0.20 USDC (`0_200_000` subunits) plus a dynamic destination chain gas fee. For a 10 USDC transfer from Ethereum to HyperCore, the protocol fee is 0.001 USDC (10 USDC × 0.0001) and an example forwarding fee is 0.216109 USDC, for a total fee of 0.217109 USDC. Because the protocol fee scales with the transfer amount and the forwarding fee is dynamic, you must recalculate `maxFee` for each transfer. For a programmatic approach, see [`calculateMaxFee`](/cctp/concepts/fees#maximum-fee-parameter) on the fees page. ### Step 3. Approve the USDC transfer To allow the `TokenMessengerV2` contract to transfer the USDC on your behalf, you need to approve the transfer. This is done by calling the `approve` function on the USDC contract. You can see an example of this contract call in the [Ethereum CCTP V2 example on GitHub](https://github.com/circlefin/solana-cctp-contracts/blob/9f8cf26d059cf8927ae0a0b351f3a7a88c7bdade/examples/v2/evm.ts#L63). ### Step 4. Sign and broadcast a `depositForBurnWithHook` transaction on the `TokenMessengerV2` contract Create a `depositForBurnWithHook` transaction for the `TokenMessengerV2` contract with the following parameters: * `amount`: The amount of USDC to transfer * `destinationDomain`: 19 (HyperEVM) * `mintRecipient`: The address of the `CctpForwarder` contract on HyperEVM * `burnToken`: The address of the USDC contract on the source chain * `destinationCaller`: The address of the `CctpForwarder` contract on HyperEVM * `maxFee`: The protocol fee + forwarding fee calculated in Step 2 * `minFinalityThreshold`: `1000` (Fast Transfer) * `hookData`: The hook data to call the `CctpForwarder` contract on HyperEVM <Warning> Always set both `mintRecipient` and `destinationCaller` to the `CctpForwarder` [contract address](/cctp/references/hypercore-contract-addresses) on HyperEVM when you transfer USDC to HyperCore. * If `destinationCaller` is wrong, the forwarder cannot complete the transfer. * If `mintRecipient` is wrong, the minted USDC is not sent to the forwarder. In either case, funds become permanently stuck and **cannot be recovered**. </Warning> The `hookData` is the data to execute the forwarder to HyperCore. The following is an example of the hook data: ```ts TypeScript theme={null} /** * Generate CCTP forwarder hook data for HyperCore * * Hook Data Format: * Field Bytes Type Index * magicBytes 24 bytes24 0 ASCII prefix "cctp-forward", followed by padding * version 4 uint32 24 * dataLength 4 uint32 28 * hyperCoreMintRecipient 20 address 32 EVM address - optional, included if requesting a deposit to HyperCore * hyperCoreDestinationDex 4 uint32 52 The destinationDexId on HyperCore (0 for perp and uint32.max for spot) */ function encodeForwardHookData( hyperCoreMintRecipient?: `0x${string}`, hyperCoreDestinationDex: number = 0, ): `0x${string}` { // Validate hex prefix if recipient provided if (hyperCoreMintRecipient && !hyperCoreMintRecipient.startsWith("0x")) { throw new Error("Address must start with 0x"); } // Magic bytes: "cctp-forward" (12 chars) padded to 24 bytes with zeros const magic = "cctp-forward"; const magicHex = Buffer.from(magic, "utf-8").toString("hex").padEnd(48, "0"); // Version: uint32 = 0 (4 bytes, big-endian) const version = "00000000"; if (!hyperCoreMintRecipient) { // No recipient: dataLength = 0, return header only (32 bytes) const dataLength = "00000000"; return `0x${magicHex}${version}${dataLength}`; } // With recipient: dataLength = 24 (20 bytes address + 4 bytes dex) const dataLength = "00000018"; // 24 in hex // Address: 20 bytes (remove 0x prefix) const address = hyperCoreMintRecipient.slice(2).toLowerCase(); // Destination DEX: uint32 big-endian // 0 = perps, 4294967295 (0xFFFFFFFF) = spot const dex = (hyperCoreDestinationDex >>> 0).toString(16).padStart(8, "0"); return `0x${magicHex}${version}${dataLength}${address}${dex}`; } ``` You can see an example of this contract call in the [Ethereum V2 example on GitHub](https://github.com/circlefin/solana-cctp-contracts/blob/9f8cf26d059cf8927ae0a0b351f3a7a88c7bdade/examples/v2/evm.ts#L105) Once the deposit transaction is confirmed, the USDC is minted on HyperEVM and automatically forwarded to your address on HyperCore. By default (when `hyperCoreDestinationDex` is `0`), deposits credit the perps balance on HyperCore. To deposit to the spot balance, set `hyperCoreDestinationDex` to `4294967295` (uint32 max value). # Transfer USDC from HyperEVM to HyperCore Source: https://developers.circle.com/cctp/howtos/transfer-usdc-from-hyperevm-to-hypercore This guide shows how to transfer USDC from HyperEVM to HyperCore using the `CoreDepositWallet` contract. <Tip> **Tip:** The `CoreDepositWallet` contract provides `deposit`, `depositFor`, and `depositWithAuth` methods. This guide uses `deposit`. All methods accept a `destinationDex` parameter (`0` for perps, `4294967295` for spot). See the [CoreDepositWallet contract interface](/cctp/references/coredepositwallet-contract-interface) for detailed information. </Tip> ## Prerequisites Before you begin, ensure that you've: * Installed [Node.js v22.18+](https://nodejs.org/) * Prepared an EVM testnet wallet with the private key available * Funded your wallet with HyperEVM testnet USDC from the [Circle Faucet](https://faucet.circle.com) * Created a new Node project and installed dependencies: ```bash theme={null} npm install viem npm install -D typescript @types/node ``` * Created a `.env` file with required environment variable: ```text theme={null} PRIVATE_KEY=0x... ``` ## Steps Use the following steps to transfer USDC from HyperEVM to HyperCore. ### Step 1. Approve the `CoreDepositWallet` to spend USDC Approve the `CoreDepositWallet` contract to transfer USDC on your behalf: ```ts TypeScript theme={null} const hash = await walletClient.writeContract({ address: USDC_ADDRESS, abi: USDC_ABI, functionName: "approve", args: [CORE_DEPOSIT_WALLET, amount], }); await publicClient.waitForTransactionReceipt({ hash }); ``` ### Step 2. Call the `deposit` function Call the `deposit` function with your desired amount and destination: ```ts TypeScript theme={null} const hash = await walletClient.writeContract({ address: CORE_DEPOSIT_WALLET, abi: CORE_DEPOSIT_WALLET_ABI, functionName: "deposit", args: [amount, destinationDex], // 0 = perps, 4294967295 = spot }); const receipt = await publicClient.waitForTransactionReceipt({ hash }); ``` The `deposit` function transfers USDC from your account to the `CoreDepositWallet` and credits your HyperCore balance. ## Full example code The following is a complete example of how to transfer USDC from HyperEVM to HyperCore. ```ts script.ts expandable theme={null} /** * Script: Call CoreDepositWallet.deposit on HyperEVM * - Approves USDC spending * - Calls deposit(amount, destinationDex) */ import { createWalletClient, createPublicClient, http, parseUnits, formatUnits, type Address, type Hex, } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { hyperliquidEvmTestnet } from "viem/chains"; // -------- Configuration -------- const config = { privateKey: (process.env.PRIVATE_KEY || "0x") as Hex, // Contract addresses (HyperEVM Testnet) coreDepositWallet: "0x0B80659a4076E9E93C7DbE0f10675A16a3e5C206" as Address, usdcToken: "0x2B3370eE501B4a559b57D449569354196457D8Ab" as Address, // Transfer parameters amount: "2", // USDC amount to deposit // HyperCore destination (0 = perps, 4294967295 = spot) destinationDex: 0, }; // -------- Main Function -------- async function main() { // Validate private key if (!config.privateKey || config.privateKey === "0x") { throw new Error("Set PRIVATE_KEY"); } // Setup account and clients const account = privateKeyToAccount(config.privateKey); const publicClient = createPublicClient({ chain: hyperliquidEvmTestnet, transport: http(), }); const walletClient = createWalletClient({ chain: hyperliquidEvmTestnet, transport: http(), account, }); const amount = parseUnits(config.amount, 6); console.log("User:", account.address); console.log("CoreDepositWallet:", config.coreDepositWallet); console.log("USDC:", config.usdcToken); console.log("Amount (USDC):", config.amount); console.log( "Destination DEX:", config.destinationDex === 0 ? "perps" : "spot", ); // Check USDC balance const balance = await publicClient.readContract({ address: config.usdcToken, abi: [ { name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "account", type: "address" }], outputs: [{ name: "", type: "uint256" }], }, ], functionName: "balanceOf", args: [account.address], }); if (balance < amount) { throw new Error( `Insufficient USDC: have ${formatUnits(balance, 6)}, need ${config.amount}`, ); } // Check current allowance const currentAllowance = await publicClient.readContract({ address: config.usdcToken, abi: [ { name: "allowance", type: "function", stateMutability: "view", inputs: [ { name: "owner", type: "address" }, { name: "spender", type: "address" }, ], outputs: [{ name: "", type: "uint256" }], }, ], functionName: "allowance", args: [account.address, config.coreDepositWallet], }); // Step 1: Approve if needed if (currentAllowance < amount) { console.log("\nApproving USDC spending..."); const hash = await walletClient.writeContract({ address: config.usdcToken, abi: [ { name: "approve", type: "function", stateMutability: "nonpayable", inputs: [ { name: "spender", type: "address" }, { name: "amount", type: "uint256" }, ], outputs: [{ name: "", type: "bool" }], }, ], functionName: "approve", args: [config.coreDepositWallet, amount], }); console.log("Approve tx hash:", hash); await publicClient.waitForTransactionReceipt({ hash }); console.log("Approval confirmed"); } else { console.log("\nSufficient allowance already exists"); } // Step 2: Deposit console.log("\nDepositing USDC to HyperCore..."); const hash = await walletClient.writeContract({ address: config.coreDepositWallet, abi: [ { name: "deposit", type: "function", stateMutability: "nonpayable", inputs: [ { name: "amount", type: "uint256" }, { name: "destinationDex", type: "uint32" }, ], outputs: [], }, ], functionName: "deposit", args: [amount, config.destinationDex], }); console.log("Deposit tx hash:", hash); // Wait for transaction receipt const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log("Status:", receipt.status === "success" ? "SUCCESS" : "FAILED"); console.log( "Block:", receipt.blockNumber, "\nGas Used:", receipt.gasUsed.toString(), ); } // Run main().catch((error) => { console.error("Error:", error.message); process.exit(1); }); ``` Run the script: ```bash theme={null} node --env-file=.env script.ts ``` # Transfer USDC from Solana to HyperCore Source: https://developers.circle.com/cctp/howtos/transfer-usdc-from-solana-to-hypercore This guide shows how to transfer USDC from Solana to HyperCore using the `TokenMessengerV2` contract. Solana's CCTP implementation does not have the `depositForBurnWithAuth`, and there is no `CctpExtension` contract for Solana. As such, transfers from Solana to HyperCore follow the standard CCTP flow, with the addition of hook data to call the `CctpForwarder` contract on HyperEVM. This guide does not provide full example code for the transfer to HyperCore from Solana. <Note> Fast Transfers from Solana to HyperEVM incur a protocol fee and a dynamic forwarding fee for the HyperEVM chain relay transaction. Fast Transfer is the default for transfers from Solana to HyperCore. </Note> ## Steps Use the following steps to transfer USDC from Solana to HyperCore. ### Step 1. Get CCTP fees from the API Query the CCTP API for the fees for transferring USDC from Solana to HyperCore. This value is passed to the `maxFee` parameter in the `depositForBurnWithHook` transaction. The following is an example request to the CCTP using source domain 5 (Solana) and destination domain 19 (HyperEVM): ```shell theme={null} curl --request GET \ --url 'https://iris-api-sandbox.circle.com/v2/burn/USDC/fees/5/19?forward=true&hyperCoreDeposit=true' \ --header 'Content-Type: application/json' ``` **Response:** ```json theme={null} [ { "finalityThreshold": 1000, // fast transfer "minimumFee": 1, // in basis points "forwardFee": { "low": 211203, "med": 216109, // 0.216109 USDC "high": 221014 } }, { "finalityThreshold": 2000, // standard transfer "minimumFee": 0, "forwardFee": { "low": 211203, "med": 216109, // 0.216109 USDC "high": 221014 } } ] ``` ### Step 2. Calculate the USDC amounts minus fees There is a protocol fee to deposit USDC from Solana to HyperEVM and a dynamic forwarding fee for the HyperEVM chain relay transaction. The CCTP fast transfer fee is 1 basis point (0.01%) of the transfer amount. The forwarding fee is 0.20 USDC (`0_200_000` subunits) plus a dynamic destination chain gas fee. For a 10 USDC transfer from Solana to HyperCore, the protocol fee is 0.001 USDC (10 USDC × 0.0001) and an example forwarding fee is 0.216109 USDC, for a total fee of 0.217109 USDC. Because the protocol fee scales with the transfer amount and the forwarding fee is dynamic, you must recalculate `maxFee` for each transfer. For a programmatic approach, see [`calculateMaxFee`](/cctp/concepts/fees#maximum-fee-parameter) on the fees page. ### Step 3. Sign and broadcast a `depositForBurnWithHook` transaction on the `TokenMessengerV2` contract Create a `depositForBurnWithHook` transaction for the `TokenMessengerV2` contract with the following parameters: * `amount`: The amount of USDC to transfer * `destinationDomain`: 19 (HyperEVM) * `mintRecipient`: The address of the `CctpForwarder` contract on HyperEVM * `destinationCaller`: The address of the `CctpForwarder` contract on HyperEVM * `maxFee`: The protocol fee + forwarding fee calculated in Step 2 * `minFinalityThreshold`: `1000` (Fast Transfer) * `hookData`: The hook data to call the `CctpForwarder` contract on HyperEVM <Warning> Always set both `mintRecipient` and `destinationCaller` to the `CctpForwarder` [contract address](/cctp/references/hypercore-contract-addresses) on HyperEVM when you transfer USDC to HyperCore. * If `destinationCaller` is wrong, the forwarder cannot complete the transfer. * If `mintRecipient` is wrong, the minted USDC is not sent to the forwarder. In either case, funds become permanently stuck and **cannot be recovered**. </Warning> The `hookData` is the data to execute the forwarder to HyperCore. The following is an example of the hook data: ```ts TypeScript theme={null} /** * Generate CCTP forwarder hook data for HyperCore * * Hook Data Format: * Field Bytes Type Index * magicBytes 24 bytes24 0 ASCII prefix "cctp-forward", followed by padding * version 4 uint32 24 * dataLength 4 uint32 28 * hyperCoreMintRecipient 20 address 32 EVM address - optional, included if requesting a deposit to HyperCore * hyperCoreDestinationDex 4 uint32 52 The destinationDexId on HyperCore (0 for perp and uint32.max for spot) */ function encodeForwardHookData( hyperCoreMintRecipient?: `0x${string}`, hyperCoreDestinationDex: number = 0, ): `0x${string}` { // Validate hex prefix if recipient provided if (hyperCoreMintRecipient && !hyperCoreMintRecipient.startsWith("0x")) { throw new Error("Address must start with 0x"); } // Magic bytes: "cctp-forward" (12 chars) padded to 24 bytes with zeros const magic = "cctp-forward"; const magicHex = Buffer.from(magic, "utf-8").toString("hex").padEnd(48, "0"); // Version: uint32 = 0 (4 bytes, big-endian) const version = "00000000"; if (!hyperCoreMintRecipient) { // No recipient: dataLength = 0, return header only (32 bytes) const dataLength = "00000000"; return `0x${magicHex}${version}${dataLength}`; } // With recipient: dataLength = 24 (20 bytes address + 4 bytes dex) const dataLength = "00000018"; // 24 in hex // Address: 20 bytes (remove 0x prefix) const address = hyperCoreMintRecipient.slice(2).toLowerCase(); // Destination DEX: uint32 big-endian // 0 = perps, 4294967295 (0xFFFFFFFF) = spot const dex = (hyperCoreDestinationDex >>> 0).toString(16).padStart(8, "0"); return `0x${magicHex}${version}${dataLength}${address}${dex}`; } ``` For full example code calling the `depositForBurnWithHook` function, see the [Solana CCTP V2 example on GitHub](https://github.com/circlefin/solana-cctp-contracts/blob/9f8cf26d059cf8927ae0a0b351f3a7a88c7bdade/examples/v2/solana.ts#L94). Once the deposit transaction is confirmed, the USDC is minted on HyperEVM and automatically forwarded to your address on HyperCore. By default (when `hyperCoreDestinationDex` is `0`), deposits credit the perps balance on HyperCore. To deposit to the spot balance, set `hyperCoreDestinationDex` to `4294967295` (uint32 max value). # How-to: Transfer USDC with the Forwarding Service Source: https://developers.circle.com/cctp/howtos/transfer-usdc-with-forwarding-service Transfer USDC Crosschain with the Circle Forwarding Service This guide shows how to transfer USDC crosschain using the [Circle Forwarding Service](/cctp/concepts/forwarding-service). This example shows a transfer from Base Sepolia to Avalanche Fuji, but you can use the same steps to transfer to any supported [destination blockchain](/cctp/concepts/supported-chains-and-domains), including Solana. When you use the Forwarding Service, Circle handles the mint transaction on the destination blockchain, eliminating the need for you to hold native tokens for gas on the destination blockchain or run multichain infrastructure. ## Prerequisites Before you start, ensure you have: * Installed [Node.js v22.18+](https://nodejs.org/) * Created a TypeScript project and installed the `viem` package. * Created a wallet with the private key available on the source chain. * Funded the wallet with testnet USDC and native tokens for gas fees on the source chain. * Created a `.env` file with your private key and recipient address. ## Steps Use the following steps to transfer USDC with the Forwarding Service. ### Step 1. Get CCTP fees from the API Query the CCTP API for the fees for transferring USDC from Base Sepolia to Avalanche Fuji. This value is passed to the `maxFee` parameter in the `depositForBurnWithHook` transaction. The following is an example reque
프로젝트로 돌아가기