Wormhole
Search…
First Transfer
A simple transfer of tokens from Ethereum to Solana
A cornerstone of cross chain apps (xDapps) is the ability to move tokens from one chain to another. Wormhole’s APIs make that a breeze.
Let’s do a simple programmatic transfer from Eth to Solana. First, we need to figure out what address on Solana where we are sending the tokens. Unlike EVM chains where the address is just the wallet address, we need to send the tokens to our recipient address associated token account for that token. We can use a couple helper functions from the Wormhole SDK to make this possible.
1
import {
2
Token,
3
ASSOCIATED_TOKEN_PROGRAM_ID,
4
TOKEN_PROGRAM_ID
5
} from '@solana/spl-token';
6
import {
7
getForeignAssetSolana,
8
hexToUint8Array,
9
nativeToHexString,
10
CHAIN_ID_ETH,
11
} from '@certusone/wormhole-sdk';
12
13
const SOLANA_TOKEN_BRIDGE_ADDRESS = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb";
14
// determine destination address - an associated token account
15
const solanaMintKey = new PublicKey(
16
(await getForeignAssetSolana(
17
connection,
18
SOLANA_TOKEN_BRIDGE_ADDRESS,
19
CHAIN_ID_ETH,
20
hexToUint8Array(nativeToHexString(tokenAddress, CHAIN_ID_ETH) || "")
21
)) || ""
22
);
23
const recipientAddress = await Token.getAssociatedTokenAddress(
24
ASSOCIATED_TOKEN_PROGRAM_ID,
25
TOKEN_PROGRAM_ID,
26
solanaMintKey,
27
recipientWalletAddress
28
);
Copied!
After we have the receipt token account on Solana, we can come back and submit the transfer message on Ethereum. This will output a log that contains a sequence number (A nonce for the message) and an emitter address (the ETH Token Bridge Address as bytes) . The sequence number and emitter address will be used to fetch a VAA after it’s been signed by Guardians.
1
import {
2
trasnferFromEth,
3
parseSequenceFromLogEth,
4
getEmitterAddressEth,
5
CHAIN_ID_SOLANA,
6
} from '@certusone/wormhole-sdk';
7
8
const ETH_TOKEN_BRIDGE_ADDRESS = "0x3ee18B2214AFF97000D974cf647E7C347E8fa585";
9
10
// Submit transaction - results in a Wormhole message being published
11
const receipt = await transferFromEth(
12
ETH_TOKEN_BRIDGE_ADDRESS,
13
signer,
14
tokenAddress,
15
amount,
16
CHAIN_ID_SOLANA,
17
recipientAddress
18
);
19
// Get the sequence number and emitter address required to fetch the signedVAA of our message
20
const sequence = parseSequenceFromLogEth(receipt, ETH_BRIDGE_ADDRESS);
21
const emitterAddress = getEmitterAddressEth(ETH_TOKEN_BRIDGE_ADDRESS);
Copied!
Once the Guardians have signed the token message, we can fetch it to use in the redeem step. If you’re a developer, you might run this as an automatic process through an application specific relayer (more on that in a later thread!)
1
import {
2
getSignedVAA,
3
} from '@certusone/wormhole-sdk';
4
5
// Fetch the signedVAA from the Wormhole Network (this may require retries while you wait for confirmation)
6
const { signedVAA } = await getSignedVAA(
7
WORMHOLE_RPC_HOST,
8
CHAIN_ID_ETH,
9
emitterAddress,
10
sequence
11
);
Copied!
Then we can post the VAA to Solana to mint the tokens. Because of the compute limit on Solana, we split the signature verification and token claim into steps. First we'll verify all the signatures and create a claim account for the Token.
1
const SOL_BRIDGE_ADDRESS = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth";
2
// On Solana, we have to post the signedVAA ourselves
3
await postVaaSolana(
4
connection, // Solana Mainnet Connection
5
wallet, //Solana Wallet Signer
6
SOL_BRIDGE_ADDRESS,
7
payerAddress,
8
signedVAA
9
);
Copied!
Finally, we can claim the tokens
1
// Finally, redeem on Solana
2
const transaction = await redeemOnSolana(
3
connection,
4
SOL_BRIDGE_ADDRESS,
5
SOL_TOKEN_BRIDGE_ADDRESS,
6
payerAddress,
7
signedVAA,
8
isSolanaNative,
9
mintAddress
10
);
11
const signed = await wallet.signTransaction(transaction);
12
const txid = await connection.sendRawTransaction(signed.serialize());
13
await connection.confirmTransaction(txid);
Copied!
Copy link