Initialize Proxy Account

Every foreign chain user requires a solana account for their identity in solana chain to make any transactions. The associated token accounts that the user possesses in solana is also created from this account. The zebec bridge program in solana provides creating a solana account for users in foreign chain user for each chain that acts as a proxy account for evm user and signs transactions on behalf of user's demand in invoking solana programs. Proxy account is derived from seed of the 32 bytes wormhole's standard address buffer derived from their native address and wormhole chain id.

Seed: [32 byte sender address, chain id]

Program Id: Solana Zebec bridge program Id

A solana proxy account can be created in following way.

const newUser = "<evm address>"

// sends payload to initialize solana accounts
const receipt = await ethClient.registerUser(newUser);

After this, Zebec evm bridge contract sends payloads to wormhole which will be signed by the validators called guardians which when signed by minimum required number of validators can be retrieved from wormhole rpc hosts. This should be posted in solana wormhole bridge. The signed vaa can be obtained in following way.

const sequence = parseSequenceFromLogEth(receipt, getBridgeAddressForChain(sourceChain));
const zebecEmitterAddress = getEmitterAddressEth(BSC_ZEBEC_BRIDGE_ADDRESS);
const { vaaBytes } = await getSignedVAAWithRetry(
   WORMHOLE_RPC_HOSTS, 
   sourceChain, 
   zebecEmitterAddress, 
   sequence
);

Zebec provides specialized zebec bridge spy relayer for relaying the message passed by its evm bridge contracts to solana bridge program as well however, that doesn't imply that they cannot be relayed manually. The sdk provides required client interfaces, factory classes and utililities for this. The spy relayer uses same sdk to relay the incomming payloads to solana.

const payerAddress = wallet.publicKey.toString();
const bridgeAddress = getBridgeAddressForChain(targetChain);

const vaaBuf = Buffer.from(vaaBytes);

setDefaultWasm("node"); // use bundler for browser

// posting vaa in solana
await postVaaSolanaWithRetry(
   connection,
   wallet.signTransaction,
   bridgeAddress,
   payerAddress,
   vaaBuf,
   MAX_VAA_UPLOAD_RETRIES_SOLANA,
);

Then you parse payload information from vaa and call method in Zebec Solana bridge program to initialize account.

const parsedVaa = parse_vaa(vaaBytes);
const parsedPayload = parseZebecPayload(Buffer.from(parsedVaa.payload));

// this initializes proxy account
const result = await solanaClient.initiallizePda(
   vaaBytes, 
   <InitializeProxyAccountPayload>parsedPayload
);

One thing you might have noticed is the payload is type cast in method params. This is because the parseZebecPayload function return a union type ParsedZebecPayload type which is a union type for all parsed payload types.

Last updated