Official Node.js SDK for Bridgfy cross-chain bridging API
npm install @bridgfy/sdk





Official Node.js SDK for the Bridgfy cross-chain bridging API. Simple, typed, and production-ready.
- š 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
``bash`
npm install @bridgfy/sdk
Or with yarn:
`bash`
yarn add @bridgfy/sdk
Or with pnpm:
`bash`
pnpm add @bridgfy/sdk
`typescript
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);
`
- Authentication
- Deposit Intents
- Simulating Deposits
- Tracking Executions
- Polling & Waiting
- Utility Functions
- Error Handling
- TypeScript Support
- Examples
Get your API key from the Bridgfy Dashboard.
`typescript
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
});
`
Create or update a deposit intent for a user. Returns a unique deposit address where users can send funds.
`typescript
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/false
`
Retrieve the current deposit intent for a user.
`typescript
const intent = await client.getDepositIntent('user-abc-123');
if (intent) {
console.log('Current deposit address:', intent.depositAddress);
console.log('Routing to:', intent.targetChainKey);
}
`
`typescript
import { ChainId } from '@bridgfy/sdk';
ChainId.Ethereum // 1
ChainId.Polygon // 137
ChainId.Base // 8453
ChainId.Arbitrum // 42161
ChainId.Avalanche // 43114
`
Preview fees and output amounts before users send funds.
`typescript
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);
`
Test different destinations by changing the override parameters:
`typescript`
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
});
Use utility functions to convert between atomic and human-readable formats:
`typescript
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);`
`typescript
const executions = await client.getExecutions('user-abc-123');
for (const exec of executions) {
console.log(${exec.id}: ${exec.status}); ${exec.fromChainKey} ā ${exec.toChainKey}
console.log(); ${exec.fromTokenSymbol} ā ${exec.toTokenSymbol}
console.log();`
}
`typescript
// 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'
});
`
`typescript
// 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
});
`
`typescript
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);
}
`
Wait for a specific execution to reach a terminal status:
`typescript
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);
`
Useful after user sends a deposit:
`typescript
// 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);
`
`typescript
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 chains
`
`typescript
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);
}
`
`typescript
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..."
`
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.
`typescript
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.
The SDK throws specific error types for different scenarios:
`typescript
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);
}
}
`
The SDK is written in TypeScript and includes complete type definitions:
`typescript
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;
`
`typescript
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});š Expected output: ${expectedOutput} USDC on Polygon
// 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();š° Gas fee: ${gasFee} USDC
// 3. Show fee breakdown
const gasFee = atomicToHuman(simulation.gasFeeRaw, 6);
console.log();š§ Provider: ${simulation.provider}
console.log();
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})ā±ļø Status: ${exec.status}
});
console.log('ā
Deposit detected, processing...');
// Poll until complete
const completed = await client.pollExecution(userId, execution.id, {
interval: 5000,
onUpdate: (exec) => console.log()ā
Transfer complete! ${outputAmount} USDC delivered
});
if (completed.status === 'SUCCESS') {
const outputAmount = atomicToHuman(completed.amountOutExpected, 6);
console.log();š Transaction: ${completed.txHash}
console.log();ā Transfer failed: ${completed.lastErrorMessage}
} else {
console.error();
}
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);
})();
`typescript
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},${exec.toTokenSymbol} on ${exec.toChainKey}
to: ,`
createdAt: formatDate(exec.createdAt),
txHash: exec.txHash
}))
};
}
`typescript
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
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');
}
For complete API documentation, visit docs.bridgfy.xyz
- š§ Email: support@bridgfy.xyz
- š Documentation: https://docs.bridgfy.xyz
- š Issues: https://github.com/bridgfy/bridgfy-backend/issues
MIT