Documentation Index Fetch the complete documentation index at: https://docs.rebelfi.io/docs/llms.txt
Use this file to discover all available pages before exploring further.
This tutorial walks through a complete integration: supplying funds, tracking yield, and unwinding positions. We’ll build a simple yield service that your application can use.
Setup
import { RebelfiClient , RebelfiError , ErrorCode } from '@rebelfi/sdk' ;
const client = new RebelfiClient ({
apiKey: process . env . REBELFI_API_KEY
});
Step 0: Register the Wallet
Register the user’s wallet before any operations:
const wallet = await client . wallets . register ({
walletAddress: userWallet ,
blockchain: 'solana' ,
userId: 'your-user-id' // optional — enables querying by userId
});
const walletId = wallet . walletId ;
You can now use walletAddress, walletId, or userId in all subsequent calls. All examples below use walletAddress.
Step 1: Discover Venues and Strategies
First, find available yield opportunities for the user:
async function getAvailableStrategies ( blockchain : 'solana' , token : string ) {
const { venues , strategyCount } = await client . venues . list ({
blockchain ,
token
});
// Flatten strategies with venue info
const strategies = venues . flatMap ( venue =>
venue . strategies . map ( strategy => ({
venueId: venue . id ,
venueName: venue . name ,
venueIcon: venue . iconUrl ,
... strategy
}))
);
// Sort by APY descending
strategies . sort (( a , b ) => b . apy - a . apy );
return strategies ;
}
// Usage
const strategies = await getAvailableStrategies ( 'solana' , 'USDC' );
console . log ( 'Best APY:' , ( strategies [ 0 ]. apy * 100 ). toFixed ( 2 ) + '%' );
Step 2: Check Existing Allocations
Before supplying, check what the user already has:
// Helper to format base units to human-readable USDC
function formatUSDC ( baseUnits : string ) : string {
return ( Number ( baseUnits ) / 1_000_000 ). toFixed ( 2 );
}
async function getUserAllocations ( walletAddress : string ) {
const { allocations , totalValue , totalYieldEarned } = await client . allocations . list ({
walletAddress
});
return {
allocations ,
summary: {
totalValue ,
totalYieldEarned ,
positionCount: allocations . length
}
};
}
// Usage
const { allocations , summary } = await getUserAllocations ( userWallet );
if ( allocations . length > 0 ) {
console . log ( `User has ${ summary . positionCount } positions` );
console . log ( `Total value: ${ formatUSDC ( summary . totalValue ) } ` );
console . log ( `Total yield: ${ formatUSDC ( summary . totalYieldEarned ) } ` );
}
Step 3: Plan a Supply Operation
Create an operation and get the unsigned transaction:
interface SupplyParams {
walletAddress : string ;
strategyId : number ;
amount : string ;
tokenAddress : string ;
}
async function planSupply ( params : SupplyParams ) {
const operation = await client . operations . supply ( params );
// Validate we got a transaction
if ( operation . transactions . length === 0 ) {
throw new Error ( 'No transactions returned' );
}
const tx = operation . transactions [ 0 ];
return {
operationId: operation . operationId ,
unsignedTransaction: tx . unsignedTransaction ,
description: tx . description ,
expiresAt: new Date ( operation . expiresAt )
};
}
// Usage
const supply = await planSupply ({
walletAddress: userWallet ,
strategyId: strategies [ 0 ]. strategyId ,
amount: '1000000000' , // 1000 USDC
tokenAddress: strategies [ 0 ]. tokenAddress
});
console . log ( 'Transaction ready:' , supply . description );
console . log ( 'Expires:' , supply . expiresAt . toISOString ());
Step 4: User Signs the Transaction
Present the transaction to the user for signing. This example uses @solana/web3.js:
import { VersionedTransaction , Connection } from '@solana/web3.js' ;
async function signAndBroadcast (
unsignedTxBase64 : string ,
wallet : { signTransaction : ( tx : VersionedTransaction ) => Promise < VersionedTransaction > }
) {
// Decode the unsigned transaction
const txBuffer = Buffer . from ( unsignedTxBase64 , 'base64' );
const transaction = VersionedTransaction . deserialize ( txBuffer );
// User signs via their wallet
const signedTx = await wallet . signTransaction ( transaction );
// Broadcast to Solana
const connection = new Connection ( 'https://api.mainnet-beta.solana.com' );
const signature = await connection . sendTransaction ( signedTx );
return signature ;
}
// Usage with a wallet adapter
const txHash = await signAndBroadcast (
supply . unsignedTransaction ,
walletAdapter
);
console . log ( 'Broadcast:' , txHash );
Step 5: Submit Transaction Hash
After broadcasting, notify RebelFi:
async function submitTransaction ( operationId : number , txHash : string ) {
const result = await client . transactions . submitHash ({
operationId ,
txHash
});
return result ;
}
// Usage
await submitTransaction ( supply . operationId , txHash );
console . log ( 'Transaction submitted, waiting for confirmation...' );
Alternatively, use submitSigned to let RebelFi broadcast the transaction for you.
Step 6: Poll for Confirmation
Wait for on-chain confirmation:
async function waitForConfirmation (
operationId : number ,
options : { timeoutMs ?: number ; pollIntervalMs ?: number } = {}
) {
const { timeoutMs = 60000 , pollIntervalMs = 2000 } = options ;
const startTime = Date . now ();
while ( Date . now () - startTime < timeoutMs ) {
const operation = await client . operations . get ( operationId );
if ( operation . status === 'CONFIRMED' ) {
return { success: true , operation };
}
// Note: cancelled operations also appear as 'FAILED'
if ( operation . status === 'FAILED' ) {
const tx = operation . transactions [ 0 ];
return {
success: false ,
error: tx ?. error || 'Operation failed or was cancelled' ,
failureCode: tx ?. failureCode ,
operation
};
}
// Wait before polling again
await new Promise ( resolve => setTimeout ( resolve , pollIntervalMs ));
}
throw new Error ( 'Timeout waiting for confirmation' );
}
// Usage
const result = await waitForConfirmation ( supply . operationId );
if ( result . success ) {
console . log ( 'Supply confirmed!' );
} else {
console . error ( 'Supply failed:' , result . error );
}
Step 7: View Updated Allocation
After confirmation, the allocation is updated:
// Get the specific allocation
const allocation = await client . allocations . get (
strategies [ 0 ]. venueId ,
userWallet
);
console . log ( 'Current position:' );
console . log ( ` Principal: ${ formatUSDC ( allocation . principal ) } ` );
console . log ( ` Current value: ${ formatUSDC ( allocation . currentValue ) } ` );
console . log ( ` Yield earned: ${ formatUSDC ( allocation . yieldEarned ) } ` );
console . log ( ` APY: ${ ( allocation . apy * 100 ). toFixed ( 2 ) } %` );
Step 8: Track Earnings Over Time
Get historical earnings data:
const earnings = await client . allocations . earnings ({
walletAddress: userWallet ,
blockchain: 'solana' ,
token: 'USDC' ,
days: 30 ,
includeBreakdown: true
});
console . log ( `Period: ${ earnings . periodStart } to ${ earnings . periodEnd } ` );
console . log ( `Total yield: ${ formatUSDC ( earnings . totalYieldEarned ) } ` );
// Daily breakdown
for ( const day of earnings . history ) {
console . log ( ` ${ day . date } : + ${ formatUSDC ( day . yieldEarned ) } ` );
}
// Per-venue breakdown
if ( earnings . byVenue ) {
for ( const venue of earnings . byVenue ) {
console . log ( ` ${ venue . venueName } : ${ formatUSDC ( venue . totalYieldEarned ) } ` );
}
}
Step 9: Unwind Position
When the user wants to withdraw:
async function unwind (
walletAddress : string ,
strategyId : number ,
amount : string
) {
// Plan the unwind
const operation = await client . operations . unwind ({
walletAddress ,
strategyId ,
amount
});
return {
operationId: operation . operationId ,
unsignedTransaction: operation . transactions [ 0 ]. unsignedTransaction ,
expiresAt: operation . expiresAt
};
}
// Unwind full position
const allocation = await client . allocations . get ( strategy . strategyId , userWallet );
const unwindOp = await unwind (
userWallet ,
allocation . strategyId ,
allocation . currentValue // Full withdrawal
);
// Sign, broadcast, and wait for confirmation (same as supply)
const txHash = await signAndBroadcast ( unwindOp . unsignedTransaction , wallet );
await submitTransaction ( unwindOp . operationId , txHash );
await waitForConfirmation ( unwindOp . operationId );
console . log ( 'Position unwound successfully' );
Complete Service Example
Here’s a complete yield service wrapping all operations:
import { RebelfiClient , RebelfiError , ErrorCode } from '@rebelfi/sdk' ;
export class YieldService {
private client : RebelfiClient ;
constructor ( apiKey : string ) {
this . client = new RebelfiClient ({ apiKey });
}
async getStrategies ( token : string = 'USDC' ) {
const { venues } = await this . client . venues . list ({
blockchain: 'solana' ,
token
});
return venues . flatMap ( v =>
v . strategies . map ( s => ({ ... s , venueName: v . name , venueId: v . id }))
);
}
async getAllocations ( walletAddress : string ) {
return this . client . allocations . list ({ walletAddress });
}
async getEarnings ( walletAddress : string , days : number = 30 ) {
return this . client . allocations . earnings ({
walletAddress ,
blockchain: 'solana' ,
token: 'USDC' ,
days ,
includeBreakdown: true
});
}
async planSupply (
walletAddress : string ,
strategyId : number ,
amount : string ,
tokenAddress : string
) {
return this . client . operations . supply ({
walletAddress ,
strategyId ,
amount ,
tokenAddress
});
}
async planUnwind (
walletAddress : string ,
strategyId : number ,
amount : string
) {
return this . client . operations . unwind ({
walletAddress ,
strategyId ,
amount
});
}
async submitTx ( operationId : number , txHash : string ) {
return this . client . transactions . submitHash ({ operationId , txHash });
}
async waitForConfirmation ( operationId : number , timeoutMs = 60000 ) {
const start = Date . now ();
while ( Date . now () - start < timeoutMs ) {
const op = await this . client . operations . get ( operationId );
if ( op . status === 'CONFIRMED' ) return { success: true , op };
// Note: cancelled operations also appear as 'FAILED'
if ( op . status === 'FAILED' ) {
return { success: false , error: op . transactions [ 0 ]?. error || 'Operation failed or was cancelled' , op };
}
await new Promise ( r => setTimeout ( r , 2000 ));
}
throw new Error ( 'Timeout' );
}
async cancelOperation ( operationId : number ) {
return this . client . operations . cancel ( operationId );
}
async recoverTransaction ( operationId : number , txHash : string ) {
return this . client . transactions . recover ( operationId , { txHash });
}
}
Next Steps
Full Walkthrough Complete integration walkthrough
TypeScript Reference Complete type definitions