Skip to main content
This guide shows how to sign and submit RebelFi transactions using Crossmint’s Wallets SDK.
For Crossmint setup, API keys, and wallet creation, see the Crossmint documentation.

Environment Requirements

Crossmint’s SDK has different signer types with different environment requirements:
Signer TypeEnvironmentUse Case
Email / PasskeyBrowser, React Native (WebView)User-facing apps
API KeyServer (Node.js)Automated / custodial flows
External WalletAnyDelegated signing
Email and Passkey signers require a browser environment. They use an iframe for TEE (Trusted Execution Environment) authentication. This won’t work in Node.js tests or server-side code.

Client-Side Flow (React / React Native)

For user-facing applications where users sign their own transactions:
import { RebelfiClient } from '@rebelfi/sdk';
import { SolanaWallet } from '@crossmint/wallets-sdk';
import type { Wallet } from '@crossmint/wallets-sdk';

const rebelfi = new RebelfiClient({ apiKey: process.env.REBELFI_API_KEY });

async function supplyWithCrossmint(
  walletAddress: string,
  strategyId: number,
  amount: string,
  tokenAddress: string,
  crossmintWallet: Wallet<'solana'>
) {
  // 1. Create supply operation (returns unsigned transaction)
  const operation = await rebelfi.operations.supply({
    walletAddress,
    strategyId,
    amount,
    tokenAddress,
  });

  // 2. Get the unsigned transaction (base64)
  const unsignedTx = operation.transactions[0].unsignedTransaction;

  // 3. Sign and broadcast via Crossmint
  const solanaWallet = SolanaWallet.from(crossmintWallet);
  const result = await solanaWallet.sendTransaction({
    serializedTransaction: unsignedTx,
  });

  // 4. Submit hash back to RebelFi
  await rebelfi.transactions.submitHash({
    operationId: operation.operationId,
    txHash: result.hash,
  });

  return {
    operationId: operation.operationId,
    txHash: result.hash,
  };
}

React Native / Expo

Crossmint uses WebView to provide browser APIs in React Native. The SDK works the same way, but requires WebView-based components. See Crossmint’s React Native SDK for setup.
// The signing code is identical - WebView handles the browser environment
const result = await solanaWallet.sendTransaction({
  serializedTransaction: unsignedTx,
});

Server-Side Flow (API Key Signer)

For automated or custodial flows where your server controls signing:
API Key signers are custodial — Crossmint signs transactions automatically without user interaction. Use this for treasury management or automated operations.
import { RebelfiClient } from '@rebelfi/sdk';
import { CrossmintWallets, createCrossmint, SolanaWallet } from '@crossmint/wallets-sdk';

const rebelfi = new RebelfiClient({ apiKey: process.env.REBELFI_API_KEY });

// Initialize Crossmint with server API key
const crossmint = createCrossmint({
  apiKey: process.env.CROSSMINT_SERVER_API_KEY, // sk_...
});
const crossmintWallets = CrossmintWallets.from(crossmint);

async function automatedSupply(
  walletLocator: string, // e.g., "email:[email protected]:solana"
  strategyId: number,
  amount: string,
  tokenAddress: string
) {
  // 1. Get the Crossmint wallet
  const wallet = await crossmintWallets.getWallet(walletLocator, {
    chain: 'solana',
  });

  // 2. Create supply operation
  const operation = await rebelfi.operations.supply({
    walletAddress: wallet.address,
    strategyId,
    amount,
    tokenAddress,
  });

  // 3. Sign and broadcast (API key signer = automatic approval)
  const solanaWallet = SolanaWallet.from(wallet);
  const result = await solanaWallet.sendTransaction({
    serializedTransaction: operation.transactions[0].unsignedTransaction,
  });

  // 4. Submit hash back to RebelFi
  await rebelfi.transactions.submitHash({
    operationId: operation.operationId,
    txHash: result.hash,
  });

  return { operationId: operation.operationId, txHash: result.hash };
}

Complete Example: Supply + Unwind

import { RebelfiClient } from '@rebelfi/sdk';
import { SolanaWallet } from '@crossmint/wallets-sdk';
import type { Wallet } from '@crossmint/wallets-sdk';

class CrossmintYieldService {
  constructor(
    private rebelfi: RebelfiClient,
    private crossmintWallet: Wallet<'solana'>
  ) {}

  private get solanaWallet() {
    return SolanaWallet.from(this.crossmintWallet);
  }

  private get walletAddress() {
    return this.crossmintWallet.address;
  }

  async supply(strategyId: number, amount: string, tokenAddress: string) {
    const operation = await this.rebelfi.operations.supply({
      walletAddress: this.walletAddress,
      strategyId,
      amount,
      tokenAddress,
    });

    const result = await this.solanaWallet.sendTransaction({
      serializedTransaction: operation.transactions[0].unsignedTransaction,
    });

    await this.rebelfi.transactions.submitHash({
      operationId: operation.operationId,
      txHash: result.hash,
    });

    return this.waitForConfirmation(operation.operationId);
  }

  async unwind(strategyId: number, amount: string) {
    const operation = await this.rebelfi.operations.unwind({
      walletAddress: this.walletAddress,
      strategyId,
      amount,
    });

    const result = await this.solanaWallet.sendTransaction({
      serializedTransaction: operation.transactions[0].unsignedTransaction,
    });

    await this.rebelfi.transactions.submitHash({
      operationId: operation.operationId,
      txHash: result.hash,
    });

    return this.waitForConfirmation(operation.operationId);
  }

  private async waitForConfirmation(operationId: number, timeoutMs = 60000) {
    const start = Date.now();
    while (Date.now() - start < timeoutMs) {
      const op = await this.rebelfi.operations.get(operationId);
      if (op.status === 'CONFIRMED') return op;
      if (op.status === 'FAILED') throw new Error(op.transactions[0]?.error);
      await new Promise((r) => setTimeout(r, 2000));
    }
    throw new Error('Timeout waiting for confirmation');
  }
}

Troubleshooting

Cause: Using email/passkey signer in Node.js or server environment.Solution: Use API Key signer for server-side, or run in browser/WebView environment.
Cause: Too much time between creating operation and signing.Solution: Sign and submit within 60 seconds of creating the operation.
Cause: Wrong wallet signing the transaction.Solution: Ensure the Crossmint wallet address matches the walletAddress passed to the operation.

Resources