Setup

For this example we’ll use @ton/ton and @ton/crypto to interact with the contract, but you can replace it with any TON library of your choice.

Make sure to install it first:

yarn add @ton/ton @ton/crypto

Interacting with the Contract

To execute a bridge transaction, send a transfer with the following payload:

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 {beginCell, toNano, Address, TonClient, internal, WalletContractV4} from '@ton/ton'
import {mnemonicToPrivateKey} from '@ton/crypto';
import getBridgeConfigs from './getBridgeConfigs'

const getJettonWalletAddress = async (tonWalletAddress, jettonMasterAddress, publicProvider) => {
  const jettonMaster = publicProvider.open(JettonMaster.create(jettonMasterAddress))

  return jettonMaster.getWalletAddress(tonWalletAddress)
}

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

  // Replace with your wallet implementation
  const tonClient = new TonClient({
    endpoint: chainConfig.rpc,
  })
  const key = await mnemonicToPrivateKey(TON_MNEMONIC);
  const workchain = 0;
  const wallet = WalletContractV4.create({
    workchain,
    publicKey: keyPair.publicKey,
  })
  const walletProvider = tonClient.open(wallet)
  const tokenConfig = chainConfig.tokens[token]
  const amountWithDecimals = +amount * 10 ** tokenConfig.decimals
  const tokenAddress = tokenConfig.address
  const bridgeContractAddress = chainConfig.contractAddress

  const jettonWalletContract = await getJettonWalletAddress(
    Address.parse(tonWalletAddress),
    Address.parse(tokenAddress),
    tonClient
  )
  const sourceAddress = Address.parse(tonWalletAddress)
  const destinationAddress = Address.parse(bridgeContractAddress)

  const forwardPayload = beginCell()
    .storeUint(BigInt(`0x${commitmentId}`), 96)
    .endCell()

  const forwardAmount = 0.02

  const body = beginCell()
    .storeUint(0xf8a7ea5, 32) // opcode for jetton transfer
    .storeUint(0, 64) // query id
    .storeCoins(BigInt(amountWithDecimals)) // jetton amount, amount * 10^9
    .storeAddress(destinationAddress) // TON wallet destination address
    .storeAddress(sourceAddress) // response excess destination
    .storeBit(0) // no custom payload
    .storeCoins(toNano(forwardAmount)) // forward amount (if >0, will send notification message)
    .storeBit(1) // we store forwardPayload as a reference
    .storeRef(forwardPayload)
    .endCell()

  const seqno: number = await walletProvider.getSeqno();

  return await walletProvider.sendTransfer({
    seqno,
    secretKey: key.secretKey,
    timeout: Math.floor(Date.now() / 1000) + 360,
    messages: [
      internal({
        to: jettonWalletContract.toString(),
        value: toNano(0.1),
        body: body,
      }),
    ],
  })
}