@bridgfy/sdk
v1.0.2
Published
Official Node.js SDK for Bridgfy cross-chain bridging API
Downloads
11
Maintainers
Readme
Bridgfy SDK
Official Node.js SDK for the Bridgfy cross-chain bridging API. Simple, typed, and production-ready.
Features
- 🔑 Simple Authentication - Just pass your API key
- 🎯 Full TypeScript Support - Complete type definitions included
- 🔄 Automatic Polling - Built-in execution status tracking
- 🛠️ Utility Functions - Helpers for common operations
- ⚡ Promise-based - Modern async/await API
- 🛡️ Error Handling - Detailed error types and messages
Installation
npm install @bridgfy/sdkOr with yarn:
yarn add @bridgfy/sdkOr with pnpm:
pnpm add @bridgfy/sdkQuick Start
import { BridgfyClient } from '@bridgfy/sdk';
// Initialize the client
const client = new BridgfyClient({
apiKey: 'bfy_your_api_key_here'
});
// Create a deposit intent
const intent = await client.createDepositIntent({
userId: 'user-123',
targetChainId: 137, // Polygon
targetTokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC
targetAddress: '0x742D35cC6634C0532925A3b844bc9E7595f0BEb8' // Recipient
});
console.log('Deposit to this address:', intent.depositAddress);
// Track executions
const executions = await client.getExecutions('user-123');
console.log('Recent transfers:', executions);Table of Contents
- Authentication
- Deposit Intents
- Simulating Deposits
- Tracking Executions
- Polling & Waiting
- Utility Functions
- Error Handling
- TypeScript Support
- Examples
Authentication
Get your API key from the Bridgfy Dashboard.
import { BridgfyClient } from '@bridgfy/sdk';
const client = new BridgfyClient({
apiKey: 'bfy_your_api_key_here',
baseUrl: 'https://api.bridgfy.xyz', // Optional, this is the default
timeout: 30000 // Optional, request timeout in ms
});Deposit Intents
Create Deposit Intent
Create or update a deposit intent for a user. Returns a unique deposit address where users can send funds.
const intent = await client.createDepositIntent({
userId: 'user-abc-123',
targetChainId: 137, // Polygon
targetTokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC on Polygon
targetAddress: '0x742D35cC6634C0532925A3b844bc9E7595f0BEb8' // Where funds should go
});
console.log('Deposit address:', intent.depositAddress);
console.log('Target chain:', intent.targetChainKey); // "polygon"
console.log('Protocol fee:', intent.protocolFeeBps); // e.g., 50 = 0.5%
console.log('Gas sponsored:', intent.sponsoredGas); // true/falseGet Deposit Intent
Retrieve the current deposit intent for a user.
const intent = await client.getDepositIntent('user-abc-123');
if (intent) {
console.log('Current deposit address:', intent.depositAddress);
console.log('Routing to:', intent.targetChainKey);
}Supported Chains
import { ChainId } from '@bridgfy/sdk';
ChainId.Ethereum // 1
ChainId.Polygon // 137
ChainId.Base // 8453
ChainId.Arbitrum // 42161
ChainId.Avalanche // 43114Simulating Deposits
Preview fees and output amounts before users send funds.
const simulation = await client.simulateDeposit({
userId: 'user-abc-123',
fromChainId: 8453, // Base
fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
amountInAtomic: '10000000', // 10 USDC (6 decimals)
overrideTargetChainId: 137, // Polygon
overrideTargetTokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC on Polygon
overrideTargetAddress: '0x742D35cC6634C0532925A3b844bc9E7595f0BEb8' // Destination wallet
});
console.log('Expected output:', simulation.amountOutExpectedAtomic);
console.log('Gas fee:', simulation.gasFeeRaw);
console.log('Provider:', simulation.provider);
console.log('Target chain:', simulation.targetChainKey);With Different Destinations
Test different destinations by changing the override parameters:
const simulation = await client.simulateDeposit({
userId: 'user-abc-123',
fromChainId: 8453,
fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
amountInAtomic: '10000000',
// Override destination for testing
overrideTargetChainId: 1, // Ethereum instead of Polygon
overrideTargetTokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
overrideTargetAddress: '0x742D35cC6634C0532925A3b844bc9E7595f0BEb8' // Destination wallet
});Human-Readable Amounts
Use utility functions to convert between atomic and human-readable formats:
import { humanToAtomic, atomicToHuman, getTokenDecimals } from '@bridgfy/sdk';
// Convert 10 USDC to atomic units
const atomicAmount = humanToAtomic(10, 6); // "10000000"
// Or use automatic decimals lookup
const decimals = getTokenDecimals('USDC'); // 6
const atomicAmount2 = humanToAtomic(10, decimals);
// Convert back to human-readable
const humanAmount = atomicToHuman('10000000', 6); // "10"
// Simulate with human-readable input
const simulation = await client.simulateDeposit({
userId: 'user-123',
fromChainId: 8453,
fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
amountInAtomic: humanToAtomic(10, 6),
overrideTargetChainId: 137, // Polygon
overrideTargetTokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC on Polygon
overrideTargetAddress: '0x742D35cC6634C0532925A3b844bc9E7595f0BEb8' // Destination wallet
});
// Display human-readable output
const outputUSDC = atomicToHuman(simulation.amountOutExpectedAtomic, 6);
console.log(`You'll receive approximately ${outputUSDC} USDC`);Tracking Executions
Get All Executions
const executions = await client.getExecutions('user-abc-123');
for (const exec of executions) {
console.log(`${exec.id}: ${exec.status}`);
console.log(` ${exec.fromChainKey} → ${exec.toChainKey}`);
console.log(` ${exec.fromTokenSymbol} → ${exec.toTokenSymbol}`);
}Filter by Status
// Get only successful executions
const successful = await client.getExecutions('user-abc-123', {
status: 'SUCCESS'
});
// Get failed executions
const failed = await client.getExecutions('user-abc-123', {
status: 'FAILED'
});Pagination
// Get first 10 executions
const page1 = await client.getExecutions('user-abc-123', {
limit: 10,
offset: 0
});
// Get next 10
const page2 = await client.getExecutions('user-abc-123', {
limit: 10,
offset: 10
});Get Specific Execution
const execution = await client.getExecution('user-abc-123', 'exec_xyz789');
if (execution) {
console.log('Status:', execution.status);
console.log('Transaction hash:', execution.txHash);
console.log('Completed at:', execution.completedAt);
}Polling & Waiting
Poll Execution Until Complete
Wait for a specific execution to reach a terminal status:
const execution = await client.pollExecution('user-abc-123', 'exec_xyz789', {
interval: 5000, // Check every 5 seconds (default)
timeout: 300000, // Give up after 5 minutes (default)
onUpdate: (exec) => {
console.log('Current status:', exec.status);
}
});
console.log('Final status:', execution.status);Wait for Any New Execution
Useful after user sends a deposit:
// User just sent funds to depositAddress
console.log('Waiting for deposit detection...');
const execution = await client.waitForExecution('user-abc-123', {
timeout: 120000, // Wait up to 2 minutes
onUpdate: (exec) => {
console.log('Detected execution:', exec.id);
console.log('Status:', exec.status);
}
});
// Now poll until complete
const completed = await client.pollExecution('user-abc-123', execution.id);
console.log('Transfer completed!', completed.status);Utility Functions
Chain Information
import { getChainInfo, CHAINS } from '@bridgfy/sdk';
const chain = getChainInfo(137);
console.log(chain.name); // "Polygon"
console.log(chain.key); // "polygon"
console.log(chain.explorerUrl); // "https://polygonscan.com"
// Access all chains
console.log(CHAINS); // Record of all supported chainsBlock Explorer Links
import { getExplorerUrl } from '@bridgfy/sdk';
const execution = await client.getExecution('user-123', 'exec_xyz');
if (execution.txHash) {
const explorerUrl = getExplorerUrl(execution.fromChainId, execution.txHash);
console.log('View on explorer:', explorerUrl);
}Status Helpers
import {
isTerminalStatus,
isSuccessStatus,
isInProgressStatus,
isFailedStatus,
getStatusMessage
} from '@bridgfy/sdk';
const execution = await client.getExecution('user-123', 'exec_xyz');
if (isTerminalStatus(execution.status)) {
console.log('Execution is complete');
}
if (isSuccessStatus(execution.status)) {
console.log('Transfer succeeded!');
}
if (isInProgressStatus(execution.status)) {
console.log('Transfer is still processing...');
}
// Get user-friendly message
const message = getStatusMessage(
execution.status,
execution.retryable,
execution.retryCount
);
console.log(message); // e.g., "Transfer complete!" or "Processing your transfer..."Address Validation and Checksumming
The SDK automatically checksums all EVM addresses according to EIP-55 before sending them to the API. This means you can provide addresses in any valid format (checksummed or not), and the SDK will handle the conversion automatically.
import { isValidAddress, toChecksumAddress, isChecksummedAddress } from '@bridgfy/sdk';
// Validate address format (accepts any valid hex format)
const address = '0x742d35cc6634c0532925a3b844bc9e7595f0beb8'; // lowercase
if (isValidAddress(address)) {
console.log('Valid Ethereum address');
}
// Convert to EIP-55 checksummed format
const checksummed = toChecksumAddress(address);
console.log(checksummed); // '0x742D35cC6634C0532925A3b844bc9E7595f0BEb8'
// Check if an address is properly checksummed
if (isChecksummedAddress('0x742D35cC6634C0532925A3b844bc9E7595f0BEb8')) {
console.log('Address is properly checksummed');
}
// Validate with checksum requirement
if (isValidAddress(address, true)) {
console.log('Valid and properly checksummed');
}Note: You don't need to manually checksum addresses when calling SDK methods like createDepositIntent() or simulateDeposit() - the SDK does this automatically.
Error Handling
The SDK throws specific error types for different scenarios:
import {
BridgfyApiError,
BridgfyConfigError,
BridgfyNetworkError,
BridgfyTimeoutError
} from '@bridgfy/sdk';
try {
const intent = await client.createDepositIntent({
userId: 'user-123',
targetChainId: 137,
targetTokenAddress: '0x...',
targetAddress: '0x...'
});
} catch (error) {
if (error instanceof BridgfyApiError) {
console.error('API Error:', error.message);
console.error('Status:', error.statusCode);
console.error('Details:', error.details);
if (error.isAuthError()) {
console.error('Invalid API key');
} else if (error.isValidationError()) {
console.error('Invalid parameters');
} else if (error.isNotFoundError()) {
console.error('Resource not found');
} else if (error.isRateLimitError()) {
console.error('Rate limit exceeded');
}
} else if (error instanceof BridgfyNetworkError) {
console.error('Network error:', error.message);
} else if (error instanceof BridgfyTimeoutError) {
console.error('Request timeout:', error.message);
} else if (error instanceof BridgfyConfigError) {
console.error('Configuration error:', error.message);
}
}TypeScript Support
The SDK is written in TypeScript and includes complete type definitions:
import {
BridgfyClient,
DepositIntent,
Execution,
SimulationResult,
ExecutionStatus,
ChainId
} from '@bridgfy/sdk';
const client = new BridgfyClient({ apiKey: 'bfy_...' });
// All methods are fully typed
const intent: DepositIntent = await client.createDepositIntent({...});
const executions: Execution[] = await client.getExecutions('user-123');
const simulation: SimulationResult = await client.simulateDeposit({...});
// Enums and types are available
const status: ExecutionStatus = 'SUCCESS';
const chainId: ChainId = ChainId.Polygon;Examples
Complete Integration Flow
import { BridgfyClient, humanToAtomic, atomicToHuman } from '@bridgfy/sdk';
const client = new BridgfyClient({
apiKey: process.env.BRIDGFY_API_KEY!
});
async function setupUserBridge(userId: string, destinationAddress: string) {
// 1. Create deposit intent
const intent = await client.createDepositIntent({
userId,
targetChainId: 137, // Polygon
targetTokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC
targetAddress: destinationAddress
});
console.log(`✅ Deposit address created: ${intent.depositAddress}`);
// 2. Simulate to show expected output
const simulation = await client.simulateDeposit({
userId,
fromChainId: 8453, // Base
fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
amountInAtomic: humanToAtomic(10, 6), // 10 USDC
overrideTargetChainId: 137, // Polygon
overrideTargetTokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC on Polygon
overrideTargetAddress: destinationAddress
});
const expectedOutput = atomicToHuman(simulation.amountOutExpectedAtomic, 6);
console.log(`📊 Expected output: ${expectedOutput} USDC on Polygon`);
// 3. Show fee breakdown
const gasFee = atomicToHuman(simulation.gasFeeRaw, 6);
console.log(`💰 Gas fee: ${gasFee} USDC`);
console.log(`🔧 Provider: ${simulation.provider}`);
return intent.depositAddress;
}
async function trackUserDeposit(userId: string) {
console.log('⏳ Waiting for deposit...');
// Wait for deposit to be detected
const execution = await client.waitForExecution(userId, {
timeout: 120000,
onUpdate: (exec) => console.log(`📡 Detected: ${exec.id}`)
});
console.log('✅ Deposit detected, processing...');
// Poll until complete
const completed = await client.pollExecution(userId, execution.id, {
interval: 5000,
onUpdate: (exec) => console.log(`⏱️ Status: ${exec.status}`)
});
if (completed.status === 'SUCCESS') {
const outputAmount = atomicToHuman(completed.amountOutExpected, 6);
console.log(`✅ Transfer complete! ${outputAmount} USDC delivered`);
console.log(`🔗 Transaction: ${completed.txHash}`);
} else {
console.error(`❌ Transfer failed: ${completed.lastErrorMessage}`);
}
return completed;
}
// Usage
(async () => {
const userId = 'user-123';
const destinationAddress = '0x742D35cC6634C0532925A3b844bc9E7595f0BEb8';
const depositAddress = await setupUserBridge(userId, destinationAddress);
console.log(`\n👉 Send USDC to: ${depositAddress}\n`);
await trackUserDeposit(userId);
})();Dashboard Integration
import { BridgfyClient, getStatusMessage, formatDate } from '@bridgfy/sdk';
const client = new BridgfyClient({ apiKey: process.env.BRIDGFY_API_KEY! });
async function getUserDashboard(userId: string) {
// Get user's deposit intent
const intent = await client.getDepositIntent(userId);
// Get execution history
const executions = await client.getExecutions(userId, { limit: 10 });
return {
depositAddress: intent.depositAddress,
targetChain: intent.targetChainKey,
recentTransfers: executions.map(exec => ({
id: exec.id,
status: exec.status,
statusMessage: getStatusMessage(exec.status, exec.retryable, exec.retryCount),
from: `${exec.fromTokenSymbol} on ${exec.fromChainKey}`,
to: `${exec.toTokenSymbol} on ${exec.toChainKey}`,
createdAt: formatDate(exec.createdAt),
txHash: exec.txHash
}))
};
}Calculate Minimum Deposit
import { BridgfyClient, humanToAtomic, BridgfyApiError } from '@bridgfy/sdk';
const client = new BridgfyClient({ apiKey: process.env.BRIDGFY_API_KEY! });
async function findMinimumDeposit(
userId: string,
fromChainId: number,
fromTokenSymbol: string
): Promise<string> {
let amount = 1; // Start with 1 token
while (amount < 1000) { // Safety limit
try {
await client.simulateDeposit({
userId,
fromChainId,
fromTokenSymbol,
amountInAtomic: humanToAtomic(amount, 6)
});
// If successful, this is viable
return `${amount} ${fromTokenSymbol}`;
} catch (error) {
if (error instanceof BridgfyApiError &&
error.details?.errorCode === 'FAILED_INSUFFICIENT_AFTER_FEES') {
// Too small, try more
amount += 1;
} else {
throw error;
}
}
}
throw new Error('Could not find minimum deposit');
}API Reference
For complete API documentation, visit docs.bridgfy.xyz
Support
- 📧 Email: [email protected]
- 📚 Documentation: https://docs.bridgfy.xyz
- 🐛 Issues: https://github.com/bridgfy/bridgfy-backend/issues
License
MIT
