Contract Overview

The Bridge program exposes the following function for bridging:

pub fn deposit_with_id(
    ctx: Context<DepositLiquidity>,
    amount: u64,
    commitment_id: u128,
)

IDL

Setup

For this example we’ll use @solana/web3.js, @solana/spl-token and @coral-xyz/anchor to interact with the contract, but you can replace it with any Solana library of your choice.

Make sure to install it first:

yarn add @solana/web3.js @solana/spl-token @coral-xyz/anchor

Set-up helpers for Solana accounts

solanaBridgeHelpers.js
import { PublicKey } from '@solana/web3.js'
import { getAssociatedTokenAddressSync } from '@solana/spl-token'
import { Buffer } from 'buffer'

export const getSolanaBridgeKey = async (bridgeContractAddress) => {
  const programId = new PublicKey(bridgeContractAddress)
  return PublicKey.findProgramAddressSync([Buffer.from('rhino_bridge')], programId)[0]
}

export const getSolanaPoolKey = async (bridgeContractAddress, mint) => {
  const programId = new PublicKey(bridgeContractAddress)
  const bridgeKey = await getSolanaBridgeKey(bridgeContractAddress)
  const mintId = new PublicKey(mint)
  return PublicKey.findProgramAddressSync([bridgeKey.toBuffer(), mintId.toBuffer()], programId)[0]
}

export const getSolanaPoolAuthority = async (bridgeContractAddress, mint) => {
  const programId = new PublicKey(bridgeContractAddress)
  const bridgeKey = await getSolanaBridgeKey(bridgeContractAddress)
  const mintId = new PublicKey(mint)
  return PublicKey.findProgramAddressSync(
    [bridgeKey.toBuffer(), mintId.toBuffer(), Buffer.from('authority')],
    programId,
  )[0]
}

export const getSolanaPoolTokenAccount = async (bridgeContractAddress, mint) => {
  const poolAuthority = await getSolanaPoolAuthority(bridgeContractAddress, mint)
  const mintId = new PublicKey(mint)
  return getAssociatedTokenAddressSync(mintId, poolAuthority, true)
}

export const getSolanaDepositorAccount = async (secondaryWalletAddress, mint) => {
  const mintId = new PublicKey(mint)
  const depositor = new PublicKey(secondaryWalletAddress)
  return getAssociatedTokenAddressSync(mintId, depositor, true)
}

Interacting with the Contract

To execute a bridge transaction, call the depositWithId (ERC20) or depositNativeWithId (native) function as follows:

The commitmentId required by the contract corresponds to the quoteId returned by the API.

To obtain the commitmentId, first request a quote from the API, then commit it. The response will include the quoteId, which should be used as the commitmentId in the contract call.

See Quickstart for details.

import {Connection, PublicKey} from '@solana/web3.js'
import {AnchorProvider, Program, BN} from '@coral-xyz/anchor'
import {
  getSolanaBridgeKey,
  getSolanaDepositorAccount,
  getSolanaPoolAuthority,
  getSolanaPoolKey,
  getSolanaPoolTokenAccount,
} from './solanaBridgeHelpers'
import {IDL} from "./idl";
import getBridgeConfigs from './getBridgeConfigs'

// Import a solana wallet / or use your wallet library
const secretKey = base58.decode(SOLANA_PRIVATE_KEY)
const keypair = Keypair.fromSecretKey(new Uint8Array(secretKey))
const wallet = new Wallet(keypair)

export const callSolanaBridgeContract = async (
  {
    token,
    chain, // SOLANA
    commitmentId,
    amount,
  }) => {
  // See API Integration -> Fetch Bridge Configs for the full implementation
  const configs = await getBridgeConfigs()
  const chainConfig = configs[chain]

  const solanaWalletAddress = wallet.publicKey.toString()

  const tokenConfig = chainConfig.tokens[token]
  const tokenAmount = +amount * 10 ** tokenConfig.decimals
  const tokenAddress = tokenConfig.address
  const bridgeContractAddress = chainConfig.contractAddress

  const connection = new Connection(chainConfig.rpc)

  const options = AnchorProvider.defaultOptions()
  const anchorProvider = new AnchorProvider(connection, wallet, options)

  const depositor = new PublicKey(solanaWalletAddress)
  const bridgeKey = await getSolanaBridgeKey(bridgeContractAddress)
  const poolKey = await getSolanaPoolKey(bridgeContractAddress, tokenAddress)
  const poolAuthority = await getSolanaPoolAuthority(bridgeContractAddress, tokenAddress)
  const poolAccount = await getSolanaPoolTokenAccount(bridgeContractAddress, tokenAddress)
  const depositorAccount = await getSolanaDepositorAccount(solanaWalletAddress, tokenAddress)

  const program = new Program(IDL, bridgeContractAddress, anchorProvider)

  const accounts = {
  bridge: bridgeKey,
  pool: poolKey,
  poolAuthority,
  poolAccount: poolAccount,
  depositor,
  mint: new PublicKey(tokenAddress),
  depositorAccount: depositorAccount,
}

  const depositTxHash = await program.methods['depositWithId'](new BN(tokenAmount), new BN(commitmentId, 'hex'))
  .accounts(accounts)
  .signers([])
  .rpc()

  await connection.getSignatureStatus(depositTxHash)

  return depositTxHash
}