syrupUSDC Native Mint/Redeem

Enable syrupUSDC deposits and withdrawals in your app via CCIP on chains other than Ethereum. For wallets, apps, DEXes, custody solutions etc.

Deposits & withdrawals for Solana & EVM chains are only available for syrupUSDC. syrupUSDT support is coming in Q2 2026.

Overview

Maple's receiver contract processes programmable token transfers via CCIP messages. The receiver contract handles two types of operations:

  • Deposits: When USDC is sent to the receiver, it processes a deposit operation

  • Withdrawals: When SyrupUSDC is sent to the receiver, it processes a withdrawal operation

This guide covers sending messages from Solana to Ethereum (testnet), but the same principles apply to EVM-to-EVM transfers with appropriate token address changes.

Step By Step Guide

1. Prerequisites

This guide uses @chainlink/ccip-sdk v0.95. The stable v1.0 release will be available shortly.

  • Node.js 20 or higher

  • @chainlink/ccip-sdk ^0.95.0 - install via npm

  • @solana/web3.js ^1.98.4

  • @solana/wallet-adapter-react (for wallet integration)

  • ethers ^6.13.4 (for EVM address conversion)

  • viem ^2.43.5 (for EVM chain interactions)

Installation

2. Receiver Contract Details

Testnet Deployment (Ethereum Sepolia)

  • Receiver Address: 0x02b6a75c5d1f430f0614dc5ac8ad5f9d35fba2c4

  • Receiver Address (bytes32): 0x00000000000000000000000002b6a75c5d1f430f0614dc5ac8ad5f9d35fba2c4

  • Pool Address: 0x3EB612858EE843eBb14Df37b9Ec2c7c82B23eE2B

  • Destination Chain: Ethereum Sepolia

  • Chain Selector: 16015286601757825753

These addresses are for testnet only. When deploying to mainnet, you must update all addresses to be mainnet from Asset Integration.

Token Addresses

Solana (Devnet):

  • USDC Mint: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU

  • Pool Token Mint: 6Sn78bdY12h6j5wVzeXqYrTZboKPqBtqjB4p5xsRNFaX

Ethereum (Sepolia Testnet):

  • USDC: Different from Solana - use the USDC contract address on Ethereum Sepolia

  • syrupUSDC: Use the syrupUSDC contract address on Ethereum Sepolia

For EVM-to-EVM deposits and withdrawals, use the appropriate USDC or syrupUSDC addresses for the destination chain from Asset Integration.

3. Message Structure

The Maple receiver contract expects a UniversalMessage struct encoded as ABI-encoded bytes:

Field Descriptions

  1. universalSenderAddress (bytes32): The Solana sender's public key converted to bytes32 format

    • Example: 2hVTZGxQZTpPjarHQsnQfnRSGSy8LPy85szn8Wy4sj5V0x193b18c1b4280b6fcb542dc733cfccc3b4e56b287e04647317bdb129685854ac

  2. pool (address): The Maple pool contract address on Ethereum

    • Testnet: 0x3EB612858EE843eBb14Df37b9Ec2c7c82B23eE2B

  3. metaData (bytes32): Used to identify the source of deposits/withdrawals. Used for incentive campaigns and support. Use 0:[your protocol name] encoded as bytes32

    • E.g. 0:maple as bytes32

    • Default: 0x0000000000000000000000000000000000000000000000000000000000000000

4. Building the Message

Step 1: Convert Solana Address to bytes32

Step 2: Encode the Struct

Step 3: Convert Receiver Address to bytes32

5. Gas Estimation

Always use estimateReceiveExecution to estimate gas limits. Never hardcode gas values as they vary based on message data, token amounts, and receiver contract complexity.

Gas estimation determines how much gas is needed for the receiver contract to execute the message on the destination chain. The CCIP SDK provides accurate gas estimation through the estimateReceiveExecution function, which should be used for every message.

Using estimateReceiveExecution

Always Estimate Gas

Critical: Always use estimateReceiveExecution to estimate gas limits. Never hardcode gas values as they vary based on message data, token amounts, and receiver contract complexity.

Gas estimation may fail in rare cases (network issues, contract not deployed, etc.). If estimation fails:

  1. Retry the estimation - Most failures are transient network issues

  2. Check receiver contract - Ensure the receiver contract is deployed and accessible

  3. Verify parameters - Ensure sender, receiver, and data are correctly formatted

  4. Use minimum safety value - Only as a last resort, use a minimum value that ensures the transaction won't fail

Important Notes:

  • SDK gas estimation is strongly preferred - it calculates the exact gas needed for your specific message

  • Fallback values are emergency-only and may be too high or too low

  • If estimation consistently fails, there may be an issue with your setup

  • The fallback 700,000 gas is a conservative safety value, not a recommended value

  • Always investigate why estimation failed before using fallback values

6. Fee Estimation

Fee estimation calculates the CCIP fee required to send the message across chains.

7. Executing the Transaction

Step 1: Generate Unsigned Transaction

Step 2: Convert to Solana Transaction

Step 3: Sign and Send

Complete Code Example

Here's a complete example integrating all the steps:

Message Monitoring via API

After sending CCIP messages, you'll want to monitor their status and display message history to users. The CCIP API provides REST endpoints for querying message transactions by sender address, receiver address, or both.

Note: This is a pre-release version of the CCIP API (v2). The public release will be published soon. The Base URL of the production API will be: https://api.ccip.cldev.cloud/v2/arrow-up-right

API Base URL (Staging)

https://api.ccip.cldev.cloud/v2/arrow-up-right

Querying Messages

The API supports querying messages with the following filters:

  • By Receiver Address: Find all messages sent to the Maple receiver contract

  • By Sender Address: Find all messages sent by a specific user

  • By Both: Find messages matching both sender and receiver

Basic Query Function

Understanding Message Statuses

The API returns messages with the following status values:

  • SENT: Transaction submitted and waiting for source chain confirmation

  • SOURCE_FINALIZED: Transaction confirmed on source chain and ready for CCIP processing

  • COMMITTED: Message committed to destination chain's commit store (CCIP v1.6 and below)

  • BLESSED: Message approved by CCIP network (CCIP v1.6 and below)

  • VERIFYING: Message is being verified by the CCIP network (CCIP v1.7+)

  • VERIFIED: Message has been verified by the CCIP network (CCIP v1.7+)

  • SUCCESS: Message successfully executed on destination chain

  • FAILED: Message execution failed but can be manually retried

Status Display Helpers

Best Practices

  1. Cache Results: Cache message queries to reduce API calls

  2. Debounce Search: Debounce user input when searching by address

  3. Handle Pagination: Always check hasNextPage before loading more

  4. Error Recovery: Implement retry logic for transient failures

  5. Status Polling: Only poll for messages that aren't in final states (SUCCESS/FAILED)

  6. Rate Limiting: Be mindful of API rate limits in production

Message Information via API

The CCIP API provides endpoints to query detailed message information by message ID, sender address, or receiver address. This is useful for building monitoring dashboards, transaction history, and status tracking in your application.

API Base URL

Note: This is a pre-release version of the CCIP API (v2). The public release will be published soon.

Get Message by Message ID

Query a specific message using its message ID:

Query Messages by Receiver Address

Get all messages sent to the Maple receiver contract:

Query Messages by Sender Address

Get all messages sent by a specific Solana address:

Polling for Message Status Updates

Poll the API to check when a message status changes:

Complete Example: Message Monitoring Hook

A React hook for monitoring messages:

Best Practices (Same as Monitoring)

  1. Rate Limiting: Be mindful of API rate limits. Implement exponential backoff for retries

  2. Caching: Cache message data to reduce API calls, especially for completed messages

  3. Polling Strategy: Only poll messages that aren't in final states (SUCCESS/FAILED)

  4. Error Handling: Implement retry logic for transient failures

  5. Pagination: Use cursors for pagination when querying multiple messages

  6. Address Format: Ensure addresses are in the correct format (lowercase for EVM, base58 for Solana)

Important Notes

Minimum Transfer Amounts

Deposits and redemptions must exceed the configured fee for that token. Transactions with amounts below the fee will require manual recovery (handled by Maple).

Before sending a crosschain deposit or redemption:

  1. Query the receiver contract for the current fee configuration

  2. Validate the user's amount exceeds the fee

  3. Display a clear error if the amount is too low

Fee amounts are configured per-token on the receiver contract. For fee queries and recovery procedures, see ​Failed Deposit/Redemption Retry and Recovery. Maple handles these edge cases with a 24h SLA, but you can as well for faster resolution.

Address Format Differences

  • Gas Estimation: Use standard EVM address format (20 bytes, 42 characters with 0x)

    • Example: 0x02b6a75c5d1f430f0614dc5ac8ad5f9d35fba2c4

  • Message Construction: Use bytes32-padded address format (32 bytes, 66 characters with 0x)

    • Example: 0x00000000000000000000000002b6a75c5d1f430f0614dc5ac8ad5f9d35fba2c4

Token Transfer Behavior

  • USDC Transfer: When USDC is sent to the receiver, it processes a deposit operation

  • SyrupUSDC Transfer: When SyrupUSDC is sent to the receiver, it processes a redemption operation

Ensure you're sending the correct token type based on the operation you want to perform.

Mainnet Deployment

All addresses in this guide are for testnet only. Before deploying to mainnet:

  1. Update receiver contract address

  2. Update pool contract address

  3. Update token addresses (USDC, SyrupUSDC) for mainnet

  4. Update destination chain selector if using a different chain

  5. Verify all addresses on mainnet explorer

All addresses are available in Asset Integration.

Gas Estimation Best Practices

Always use estimateReceiveExecution to estimate gas limits. Never hardcode gas values.

Key Points:

  • Always estimate: Use estimateReceiveExecution for every message

  • Sender required: Include the sender address for accurate Solana-to-EVM estimation

  • API signature: Use estimateReceiveExecution({ source, dest, routerOrRamp, message })

  • Validate estimates: Check that estimates are reasonable (not zero, not extremely high)

  • Handle failures: If estimation fails, retry before using fallback values

  • Fallback value: 700,000 gas is a conservative fallback for emergency cases, not a recommended value

Why estimation is important:

  • Gas requirements vary based on message data size

  • SyrupUSDC Contract state can cause variable gas usage

  • Other conditions can influence gas requirements

If estimation fails:

  1. Check network connectivity

  2. Verify receiver contract is deployed and accessible

  3. Ensure all parameters (sender, receiver, data) are correct

  4. Retry the estimation (most failures are transient)

  5. Only use fallback values as a last resort

Out-of-Order Execution

Always set allowOutOfOrderExecution: true

Error Handling

Implement comprehensive error handling for:

  • User transaction rejection

  • Insufficient funds (SOL for fees, tokens for transfer)

  • Network errors

  • Gas estimation failures

  • Transaction confirmation failures

Message Tracking

After sending, track your message using the CCIP Explorer:

  • URL: https://ccip.chain.link/msg/{messageId}

  • The message ID is extracted from the transaction logs after confirmation

Resources & Contact

Last updated

Was this helpful?