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 the API bridge example 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
}