Skip to main content

Overview

You can bridge tokens from any EVM-compatible chain to Solana. The process is similar to EVM-to-EVM transfers, but you must provide a Solana address as the recipient.

Complete Example: Polygon USDC to Solana USDC

This example transfers 0.2 USDC from Polygon to Solana.
poly-usdc-to-sol-usdc.ts
import 'dotenv/config';
import {
  ethers,
  Wallet,
  TransactionResponse,
  TransactionReceipt,
  TransactionRequest
} from "ethers";
import { createDebridgeBridgeOrder } from '../../utils/deBridge/createDeBridgeOrder';
import { deBridgeOrderInput } from '../../types';
import { getEnvConfig, getJsonRpcProviders } from '../../utils';
import { USDC } from '../../utils/tokens';
import { CHAIN_IDS } from '../../utils/chains';

async function main() {
  const { privateKey } = getEnvConfig();
  const { polygonProvider } = await getJsonRpcProviders();

  // Setup wallet and signer
  const wallet = new Wallet(privateKey);
  const signer = wallet.connect(polygonProvider);
  const senderAddress = await signer.getAddress();
  console.log(`Wallet Address (Signer): ${senderAddress}`);

  // Prepare order parameters
  const usdcDecimals = 6;
  const amountToSend = "0.2";
  const solUserAddress = "862oLANNqhdXyUCwLJPBqUHrScrqNR4yoGWGTxjZftKs";

  const amountInAtomicUnit = ethers.parseUnits(amountToSend, usdcDecimals);

  const orderInput: deBridgeOrderInput = {
    srcChainId: CHAIN_IDS.Polygon.toString(),
    srcChainTokenIn: USDC.POLYGON,
    srcChainTokenInAmount: amountInAtomicUnit.toString(),
    dstChainId: CHAIN_IDS.Solana.toString(),
    dstChainTokenOut: USDC.SOLANA,
    dstChainTokenOutRecipient: solUserAddress,
    account: senderAddress,
    srcChainOrderAuthorityAddress: wallet.address,
    dstChainOrderAuthorityAddress: solUserAddress,
    affiliateFeePercent: 0.1,
    affiliateFeeRecipient: wallet.address,
  };

  console.log("Creating deBridge order...");
  const order = await createDebridgeBridgeOrder(orderInput);

  if (!order?.tx?.to || !order?.tx?.data) {
    throw new Error("Invalid transaction request from createDebridgeBridgeOrder");
  }

  console.log("Order Estimation:", order.estimation);
  const transactionRequest: TransactionRequest = order.tx;

  const spenderAddress = transactionRequest.to;
  if (!spenderAddress) {
    throw new Error("Missing spender address");
  }

  // Send bridge transaction
  try {
    console.log("Sending bridge transaction...");
    const txResponse: TransactionResponse = await signer.sendTransaction(transactionRequest);

    console.log(`Transaction sent: ${txResponse.hash}`);
    console.log(`View on Polygonscan: https://polygonscan.com/tx/${txResponse.hash}`);

    const txReceipt: TransactionReceipt | null = await txResponse.wait();

    if (txReceipt) {
      console.log(`Status: ${txReceipt.status === 1 ? 'Success' : 'Failed'}`);
      console.log(`Block: ${txReceipt.blockNumber}`);
      console.log(`Gas used: ${txReceipt.gasUsed.toString()}`);
    } else {
      console.error("Transaction receipt was null");
    }
  } catch (error) {
    console.error("Error sending transaction:", error);
    process.exitCode = 1;
  }
}

main().catch((error) => {
  console.error("Fatal error:", error);
  process.exitCode = 1;
});

Key Differences from EVM-to-EVM

Solana Address Format

Solana addresses are base58-encoded strings (32-44 characters):
// Solana address format
const solanaAddress = "862oLANNqhdXyUCwLJPBqUHrScrqNR4yoGWGTxjZftKs";

// Use as recipient
const orderInput = {
  // ...
  dstChainId: CHAIN_IDS.Solana.toString(),
  dstChainTokenOut: USDC.SOLANA,
  dstChainTokenOutRecipient: solanaAddress,
  dstChainOrderAuthorityAddress: solanaAddress,
};

Authority Addresses

For cross-chain orders to Solana, set dstChainOrderAuthorityAddress to the Solana recipient address.
const orderInput: deBridgeOrderInput = {
  srcChainId: CHAIN_IDS.Polygon.toString(),
  srcChainTokenIn: USDC.POLYGON,
  srcChainTokenInAmount: amountInAtomicUnit.toString(),
  dstChainId: CHAIN_IDS.Solana.toString(),
  dstChainTokenOut: USDC.SOLANA,
  dstChainTokenOutRecipient: solanaAddress,
  account: evmSenderAddress,
  srcChainOrderAuthorityAddress: evmSenderAddress,
  dstChainOrderAuthorityAddress: solanaAddress, // Solana address
};

Supported Token Types

USDC Transfers

Transfer USDC from any EVM chain to Solana:
import { USDC } from '../../utils/tokens';

const orderInput = {
  srcChainId: CHAIN_IDS.Polygon.toString(),
  srcChainTokenIn: USDC.POLYGON,
  // ...
  dstChainId: CHAIN_IDS.Solana.toString(),
  dstChainTokenOut: USDC.SOLANA,
};

Native Token Swaps

Bridge and swap to Solana native tokens:
poly-usdc-to-wsol.ts
const orderInput: deBridgeOrderInput = {
  srcChainId: CHAIN_IDS.Polygon.toString(),
  srcChainTokenIn: USDC.POLYGON,
  srcChainTokenInAmount: amountInAtomicUnit.toString(),
  dstChainId: CHAIN_IDS.Solana.toString(),
  dstChainTokenOut: "So11111111111111111111111111111111111111112", // wSOL
  dstChainTokenOutRecipient: solanaAddress,
  account: senderAddress,
};

Example: Base to Solana

usdc-base-to-sol.ts
const { baseProvider } = await getJsonRpcProviders();
const signer = wallet.connect(baseProvider);

const orderInput: deBridgeOrderInput = {
  srcChainId: CHAIN_IDS.Base.toString(),
  srcChainTokenIn: USDC.BASE,
  srcChainTokenInAmount: ethers.parseUnits("1", 6).toString(),
  dstChainId: CHAIN_IDS.Solana.toString(),
  dstChainTokenOut: USDC.SOLANA,
  dstChainTokenOutRecipient: solanaAddress,
  account: senderAddress,
  srcChainOrderAuthorityAddress: wallet.address,
  dstChainOrderAuthorityAddress: solanaAddress,
};

Affiliate Fees

You can earn fees on EVM-to-Solana transfers:
const orderInput: deBridgeOrderInput = {
  // ... other parameters
  affiliateFeePercent: 0.1, // 0.1% fee
  affiliateFeeRecipient: wallet.address, // Your EVM address
};
Affiliate fees are collected on the source chain (EVM) in the source token.

Validation

Validate Solana Address

Ensure the Solana address is valid:
const SOLANA_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;

function isValidSolanaAddress(address: string): boolean {
  return SOLANA_ADDRESS_REGEX.test(address);
}

const solanaAddress = "862oLANNqhdXyUCwLJPBqUHrScrqNR4yoGWGTxjZftKs";
if (!isValidSolanaAddress(solanaAddress)) {
  throw new Error("Invalid Solana address");
}

Verify Token Addresses

// Solana USDC address
const SOLANA_USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

// Wrapped SOL address
const WRAPPED_SOL = "So11111111111111111111111111111111111111112";

const orderInput = {
  // ...
  dstChainTokenOut: SOLANA_USDC,
};

Transaction Flow

1

Create order

Call createDebridgeBridgeOrder with EVM source and Solana destination
2

Approve tokens (if needed)

Approve the deBridge contract to spend your tokens on the EVM chain
3

Submit transaction

Send the transaction on the EVM source chain
4

Wait for fulfillment

Tokens arrive in the Solana recipient’s wallet after the order is fulfilled

Monitoring Orders

Track your cross-chain order status:
import { getOrderStatus } from '../../utils/deBridge/orderStatus';

const txHash = txResponse.hash;

// Wait a few seconds for order to be created
await new Promise(resolve => setTimeout(resolve, 5000));

const orderStatus = await getOrderStatus({
  srcChainTxHash: txHash,
  srcChainId: CHAIN_IDS.Polygon.toString(),
});

console.log("Order status:", orderStatus.status);
if (orderStatus.dstChainTxHash) {
  console.log(`Solana tx: https://solscan.io/tx/${orderStatus.dstChainTxHash}`);
}

Common Token Addresses

TokenSolana AddressDecimals
USDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v6
wSOLSo111111111111111111111111111111111111111129
USDTEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB6

Best Practices

Always validate the Solana recipient address format:
if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(solanaAddress)) {
  throw new Error("Invalid Solana address format");
}
Solana chain ID in deBridge is 7565164:
import { CHAIN_IDS } from '../../utils/chains';

const orderInput = {
  dstChainId: CHAIN_IDS.Solana.toString(), // "7565164"
};
Set destination authority to the Solana recipient:
const orderInput = {
  dstChainTokenOutRecipient: solanaAddress,
  dstChainOrderAuthorityAddress: solanaAddress, // Same as recipient
};

Troubleshooting

Ensure the Solana recipient address is a valid base58-encoded public key.

Common Issues

Invalid Solana address: Verify the address format:
const solanaAddress = "862oLANNqhdXyUCwLJPBqUHrScrqNR4yoGWGTxjZftKs";
console.log("Address length:", solanaAddress.length); // Should be 32-44
Wrong token address: Use the correct Solana token address:
// Correct: Solana USDC
const dstToken = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

// Incorrect: Using EVM USDC address
const dstToken = "0x...";
Authority address mismatch: Ensure both recipient and authority are Solana addresses:
const orderInput = {
  dstChainTokenOutRecipient: solanaAddress, // Solana address
  dstChainOrderAuthorityAddress: solanaAddress, // Must be Solana address too
};

Next Steps

Build docs developers (and LLMs) love