Page cover

Developer guide

API Documentation

The Genius Bridge Protocol provides a comprehensive REST API for developers to integrate cross-chain functionality into their applications. Our API is designed for simplicity, reliability, and performance.

Base URLs

  • Production: https://api.geniusbridge.com/v1

  • Staging: https://genius-bridge-staging-894762848.us-east-2.elb.amazonaws.com/quoting

Endpoints

TODO: add correct link here

The details of the various available endpoints are present at here

SDK integration

Installation

# JavaScript/TypeScript
npm install genius-bridge-sdk

Basic Setup

TODO: to add

Executing Solana transactions

When executing cross-chain swaps involving Solana, the GBP API returns an array of base58-encoded Solana transactions that must be executed in a specific sequence. These transactions are designed to work atomically using Jito bundles for optimal execution.

Transaction Types

  1. Swap Transactions (all except last): Convert user's desired token to USDC via aggregators

  2. Order Creation (last transaction): Creates an order on the Genius Solana Pool

Transactions must be executed in the exact order received:

// ❌ Don't execute in parallel
await Promise.all(transactions.map(tx => connection.sendTransaction(tx)));

// ⚠️ Execute sequentially, but not recommended
for (const transaction of transactions) {
  await connection.sendTransaction(transaction);
}

Atomic Execution with Jito Bundles

For optimal execution, use Jito bundles to ensure atomicity. Details on using jito can be found here.

Here is a sample implementation of the transaction execution via jito

import {
  Connection,
  Keypair,
  PublicKey,
  SystemProgram,
  TransactionMessage,
  VersionedTransaction,
} from '@solana/web3.js';
import bs58 from 'bs58';

export class JitoService {
  private readonly DEFAULT_JITO_FEE = 200000;
  private readonly jitoTipAccounts = [
    'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt',
    'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh',
  ];
  private readonly jitoEndpoints = [
    'https://ny.mainnet.block-engine.jito.wtf/api/v1/bundles',
    'https://tokyo.mainnet.block-engine.jito.wtf/api/v1/bundles',
  ];

  constructor() {}

  /**
   * Gets a random validator key from the validator list
   */
  private getRandomValidatorKey(): PublicKey {
    const randomValidator =
      this.jitoTipAccounts[
        Math.floor(Math.random() * this.jitoTipAccounts.length)
      ];
    return new PublicKey(randomValidator);
  }

  /**
   * Bundles transactions for Jito processing
   */
  public async bundle(
    txs: VersionedTransaction[],
    keypair: Keypair,
    connection: Connection,
    additionalSigners: Keypair[] = [],
  ): Promise<string[]> {
    const abortController = new AbortController();

    try {
      const txNum = Math.ceil(txs.length / 3);
      let successNum = 0;
      const results = [];

      const latestBlockhash = await connection.getLatestBlockhash('confirmed');
      for (let i = 0; i < txNum; i++) {
        const upperIndex = (i + 1) * 3;
        const downIndex = i * 3;
        const newTxs = [];

        for (let j = downIndex; j < upperIndex; j++) {
          if (txs[j]) {
            const message = txs[j].message;
            message.recentBlockhash = latestBlockhash.blockhash;
            const txn = new VersionedTransaction(message);
            txn.sign([keypair]);
            try {
              additionalSigners.forEach((signer) => {
                txn.sign([signer]);
              });
            } catch (error) {
              console.log(
                `Failed to sign transaction for index ${j}: `,
                error,
              );
            }
            newTxs.push(txn);
          }
        }

        const success = await this.bulldozer(
          newTxs,
          keypair,
          connection,
          abortController.signal,
        );
        const { success: successValue } = success;
        console.log('successfully finished bulldozer', success);

        if (success && successValue > 0) successNum += 1;
        results.push(success);
      }
      if (successNum == 0) {
        throw new Error('No successful responses received from Jito');
      }
      const successResults = results?.[0]?.signatures?.map((signature) => {
        return signature;
      });
      if (!successResults || successResults.length == 0) {
        throw new Error(
          'Executing Order SOLANA No successful responses received from Jito - transactions failed',
        );
      }
      return successResults;
    } catch (error) {
      console.log(
        'Executing Order SOLANA JITO Error during transaction execution',
        error,
      );
      return [];
    } finally {
      abortController.abort();
    }
  }

  /**
   * Send transactions to Jito block engine
   */
  public async bulldozer(
    txs: VersionedTransaction[],
    payer: Keypair,
    connection: Connection,
    abortSignal: AbortSignal,
  ) {
    try {
      // Get dynamic JITO fee instead of using constant
      const jitoFee = this.DEFAULT_JITO_FEE;

      const jitoFeeWallet = this.getRandomValidatorKey();
      const latestBlockhash = await connection.getLatestBlockhash('confirmed');
      const jitTipTxFeeMessage = new TransactionMessage({
        payerKey: payer.publicKey,
        recentBlockhash: latestBlockhash.blockhash,
        instructions: [
          SystemProgram.transfer({
            fromPubkey: payer.publicKey,
            toPubkey: jitoFeeWallet,
            lamports: jitoFee,
          }),
        ],
      }).compileToV0Message();

      const jitoFeeTx = new VersionedTransaction(jitTipTxFeeMessage);
      jitoFeeTx.sign([payer]);

      const serializedJitoFeeTx = bs58.encode(jitoFeeTx.serialize());
      const serializedTransactions = [
        serializedJitoFeeTx,
        ...txs.map((tx: VersionedTransaction) => bs58.encode(tx.serialize())),
      ];

      const requests = this.jitoEndpoints.map(async (url) => {
        const response = await fetch(url, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            jsonrpc: '2.0',
            id: 1,
            method: 'sendBundle',
            params: [serializedTransactions],
          }),
          signal: abortSignal,
        });

        if (!response.ok) {
          console.log('not okay response for url', url);
          return null;
        }

        return response.json();
      });
      const results = await Promise.all(requests.map((p) => p.catch((e) => e)));
      console.log('Executing Order SOLANA jitoresults', { results });

      const successfulResults = results
        .filter((result) => result !== null)
        .filter((result) => !(result instanceof Error));

      if (successfulResults.length > 0) {
        txs.map((tx) =>
          console.log(
            `TX Confirmed: https://solscan.io/tx/${bs58.encode(
              tx.signatures[0],
            )}`,
          ),
        );

        return {
          success: 1,
          signatures: txs.map((tx) => bs58.encode(tx.signatures[0])),
          links: txs.map(
            (tx) => `https://solscan.io/tx/${bs58.encode(tx.signatures[0])}`,
          ),
        };
      } else {
        console.log(`No successful responses received for jito`);
      }

      return {
        success: 0,
        error: 'No successful responses received for jito',
      };
    } catch (error) {
      console.log(
        'Executing Order SOLANA JITO Error during transaction execution',
        error,
      );
      return {
        success: 0,
        error,
      };
    }
  }
}

Last updated