Skip to content
/ sdk Public

Agglayer SDK — Unified Client Interface for Native and Aggregator Bridging

License

Notifications You must be signed in to change notification settings

agglayer/sdk

Repository files navigation

AggLayer SDK

License: Source Available TypeScript Node.js NPM Version

A comprehensive TypeScript SDK for interacting with the AggLayer ecosystem, providing seamless integration with ARC API services and blockchain operations. Engineered with enterprise-grade architecture, flexible zero-config setup, strict type safety, and exceptional developer experience.

🚀 Quick Start

Installation

# Production (stable) - NOT YET AVAILABLE
npm install @agglayer/sdk

# Beta (testing)
npm install @agglayer/sdk@beta

Basic Usage

import { AggLayerSDK, SDK_MODES } from '@agglayer/sdk';

// 🎯 NEW: Flexible Configuration - Zero setup required!
// No configuration needed - uses intelligent defaults
const sdk = new AggLayerSDK();

// Or explicitly configure modes and settings
const sdkWithConfig = new AggLayerSDK({
  mode: [SDK_MODES.CORE, SDK_MODES.NATIVE],
  core: {
    apiBaseUrl: 'https://api.agglayer.com',
    apiTimeout: 30000,
  },
  native: {
    defaultNetwork: 1, // Ethereum mainnet
  },
});

// Access modules
const core = sdk.getCore();
const native = sdkWithConfig.getNative();

Usage Examples

Core Module - ARC API Operations

The Core module provides high-level abstractions for AggLayer's ARC API, enabling route discovery, transaction building, and chain metadata management.

Chain & Token Metadata

const core = sdk.getCore();

// Retrieve metadata for all supported chains
const chains = await core.getAllChains();
console.log(`Found ${chains.chains.length} supported chains`);

// Get specific chain metadata by Chain ID
const chainData = await core.getChainMetadataByChainIds([1, 137, 11155111]);
console.log('Chain metadata:', chainData);

// Get all tokens grouped by Chain (expensive operation - use sparingly)
const allTokens = await core.getAllTokens();

// Recommended: Get chain data with tokens for specific chains
const chainTokenData = await core.getChainDataAndTokensByChainIds([1, 137]);

// NOTE: All above functions manage pagination internally

Route Discovery & Transaction Building

// Find optimal bridging routes
const routes = await core.getRoutes({
  fromChainId: 1, // Ethereum Mainnet
  toChainId: 137, // Polygon
  fromTokenAddress: '0xA0b86a33E6441b8c4C8C0e4b8c4C8C0e4b8c4C8C0',
  toTokenAddress: '0xB0b86a33E6441b8c4C8C0e4b8c4C8C0e4b8c4C8C0',
  amount: '1000000000000000000', // 1 token in wei
  fromAddress: '0x2254E4D1B41F2Dd3969a79b994E6ee8C3C6F2C71',
  slippage: 0.5, // 0.5% slippage tolerance
});

// Get unsigned transaction from route
const unsignedTx = await core.getUnsignedTransaction(routes);
console.log('Transaction data:', unsignedTx.data);

// Build claim transaction for completed bridge
const claimTx = await core.getClaimUnsignedTransaction({
  sourceNetworkId: 1,
  depositCount: 12345,
});

NOTE: getClaimUnsignedTransaction() expects Agglayer Network ID, not Chain ID

Transaction History & Monitoring

// Get transaction history with pagination
const transactions = await core.getTransactions({
  limit: 50,
  startAfter: 'nextStartAfterCursor', // cursor-based pagination
});

console.log(`Retrieved ${transactions.transactions.length} transactions`);

Native Module - Blockchain Operations

The Native module provides direct blockchain interaction capabilities with agglayer chains. Majority of interaction will happen via the ERC20 class

Network & Balance Management

const native = sdk.getNative();

const chainDetails = getNetwork(1);
// Get native token balance (ETH, MATIC, etc.)
const nativeBalance = await native.getNativeBalance(
  '0xFromAddress12345678901234567890123456789012345',
  1
);
console.log(`ETH balance: ${nativeBalance} wei`);

// Access chain registry for network information
const chainRegistry = native.getChainRegistry();
const ethereumConfig = chainRegistry.getChain(1);
const ethereumConfig = native.getNetwork(1); // OR for convinence
console.log(`RPC URL: ${sepoliaConfig.rpcUrl}`);

ERC20 Token Operations (balance, approve, transfer)

// Create ERC20 instance for USDC on Sepolia
const usdc = native.erc20(
  '0x44499312f493F62f2DFd3C6435Ca3603EbFCeeBa',
  11155111
);

// Read operations
const balance = await usdc.getBalance(
  '0xFromAddress12345678901234567890123456789012345'
);
const allowance = await usdc.getAllowance(
  '0xFromAddress12345678901234567890123456789012345', // owner
  '0x1234567890123456789012345678901234567890' // spender
);

// Build approve transaction (not executed)
const approveTx = await usdc.buildApprove(
  '0xSpenderAddress1234567890123456789012345678901', // spender
  '1000000', // 1 USDC allowance
  '0xFromAddress12345678901234567890123456789012345' // from
);

// Build transaction parameters (not executed)
const transferTx = await usdc.buildTransfer(
  '0xRecipientAddress123456789012345678901234567890',
  '1000000', // 1 USDC (6 decimals)
  '0xFromAddress12345678901234567890123456789012345' // from
);

// Build transferFrom transaction
const transferFromTx = await usdc.buildTransferFrom(
  '0xFromAddress12345678901234567890123456789012345', // from
  '0xToAddress1234567890123456789012345678901234567', // to
  '500000', // 0.5 USDC
  '0xFromAddress12345678901234567890123456789012345' // spender
);

Cross-Chain Bridge Operations

// Direct token bridging via ERC20 instance
const bridgeTx = await usdc.bridgeTo(
  137, // Polygon destination
  '0xRecipientOnPolygon1234567890123456789012345678',
  '1000000', // 1 USDC
  '0xFromAddress12345678901234567890123456789012345', // from
  {
    forceUpdateGlobalExitRoot: true,
    permitData: '0x', // optional permit data
  }
);

// Advanced bridge operations via Bridge instance
const bridge = native.bridge(
  '0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582', // bridge contract
  11155111 // Sepolia
);

// Build bridge asset transaction
const bridgeAssetTx = await bridge.buildBridgeAsset(
  {
    destinationNetwork: 137,
    destinationAddress: '0xRecipientAddress123456789012345678901234567890',
    amount: '1000000000000000000', // 1 token in wei
    token: '0x44499312f493F62f2DFd3C6435Ca3603EbFCeeBa',
    forceUpdateGlobalExitRoot: true,
  },
  '0xFromAddress12345678901234567890123456789012345'
);

// Build claim transaction from bridge tx hash
const claimAssetTx = await bridge.buildClaimAssetFromHash(
  '0xBridgeTxHash123456789012345678901234567890123456789012345678',
  11155111, // source network where bridge tx occurred
  10000, // leaf index for the claim proof
  0, // bridge event index in tx (usually 0)
  '0xFromAddress12345678901234567890123456789012345' // claimer address
);

// Check if bridge deposit is already claimed
const isClaimed = await bridge.isClaimed({
  leafIndex: 12345,
  sourceBridgeNetwork: 11155111,
});

// Get wrapped token address on destination chain
const wrappedToken = await bridge.getWrappedTokenAddress({
  originNetwork: 11155111,
  originTokenAddress: '0x44499312f493F62f2DFd3C6435Ca3603EbFCeeBa',
});

Bridge Message Operations

// Build bridge message transaction (for arbitrary data)
const bridgeMessageTx = await bridge.buildBridgeMessage(
  {
    destinationNetwork: 137,
    destinationAddress: '0xRecipientContract123456789012345678901234567',
    forceUpdateGlobalExitRoot: true,
    metadata: '0x1234', // arbitrary data payload
  },
  '0xFromAddress12345678901234567890123456789012345'
);

// Build claim message transaction from bridge tx hash
const claimMessageTx = await bridge.buildClaimMessageFromHash(
  '0xBridgeMessageTxHash12345678901234567890123456789012345678901234',
  11155111, // source network
  10000, // leaf index for the claim proof
  0, // message event index
  '0xFromAddress12345678901234567890123456789012345' // claimer
);

⚙️ Configuration

SDK Configuration Options

The SDK provides comprehensive configuration capabilities for both modules with sensible defaults and extensive customization options.

Complete Configuration Example

import { AggLayerSDK, SDK_MODES } from '@agglayer/sdk';

const sdk = new AggLayerSDK({
  // Module Selection - Choose which modules to enable
  mode: [SDK_MODES.CORE, SDK_MODES.NATIVE],

  // Core Module Configuration
  core: {
    // ARC API Configuration
    apiBaseUrl: 'https://api.agglayer.com', // Default: 'https://api.agglayer.com'
    apiTimeout: 30000, // Default: 30000 (30 seconds)
    // Implementation pending for websocket
    // websocketBaseUrl: 'wss://ws.agglayer.com', // Optional: For transactions history
  },

  // Native Module Configuration
  native: {
    // Default network for operations
    defaultNetwork: 1, // Default: 1 (Ethereum)

    // Custom chain configurations
    chains: [
      {
        chainId: 1,
        networkId: 1,
        name: 'Ethereum Mainnet',
        rpcUrl: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key',
        nativeCurrency: {
          name: 'Ether',
          symbol: 'ETH',
          decimals: 18,
        },
        blockExplorer: {
          name: 'Etherscan',
          url: 'https://etherscan.io',
        },
        bridgeAddress: '0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe',
        proofApiUrl: 'https://proof-api.polygonzkevmchain.com',
        isTestnet: false,
      },
      {
        chainId: 137,
        networkId: 137,
        name: 'Polygon Mainnet',
        rpcUrl: 'https://polygon-mainnet.g.alchemy.com/v2/your-api-key',
        nativeCurrency: {
          name: 'MATIC',
          symbol: 'MATIC',
          decimals: 18,
        },
        bridgeAddress: '0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe',
        isTestnet: false,
      },
    ],

    // Override RPC URLs for existing chains
    customRpcUrls: {
      1: 'https://your-premium-ethereum-rpc.com',
      137: 'https://your-premium-polygon-rpc.com',
      11155111: 'https://sepolia.infura.io/v3/your-project-id',
    },
  },
});

Core Module Configuration

interface CoreConfig {
  apiBaseUrl?: string; // ARC API base URL
  apiTimeout?: number; // Request timeout in milliseconds
  // websocketBaseUrl?: string;  // WebSocket endpoint for real-time updates
}

Default Values:

  • apiBaseUrl: 'https://arc-api.polygon.technology'
  • apiTimeout: 30000 (30 seconds)

Native Module Configuration

interface NativeConfig {
  defaultNetwork?: number; // Default chain ID for operations
  chains?: ChainConfig[]; // Custom chain configurations
  customRpcUrls?: Record<number, string>; // Override RPC URLs by chain ID
}

interface ChainConfig {
  chainId: number; // EIP-155 chain identifier
  networkId: number; // Network identifier (usually same as chainId)
  name: string; // Human-readable chain name
  rpcUrl: string; // RPC endpoint URL
  nativeCurrency: {
    // Native token configuration
    name: string;
    symbol: string;
    decimals: number;
  };
  blockExplorer?: {
    // Optional block explorer
    name: string;
    url: string;
  };
  bridgeAddress?: string; // Bridge contract address
  proofApiUrl?: string; // Proof generation API endpoint
  isTestnet?: boolean; // Network type flag
  isLocal?: boolean; // Local development network flag
}

Default Values:

  • defaultNetwork: 1 (Ethereum mainnet)
  • chains: Built-in registry with major networks
  • customRpcUrls: {}

Module-Specific Configurations

Core-Only Setup (API Integration)

const coreOnlySDK = new AggLayerSDK({
  mode: [SDK_MODES.CORE],
  core: {
    apiBaseUrl: 'https://api.agglayer.com',
    apiTimeout: 45000, // Increased timeout for complex operations
    // websocketBaseUrl: 'wss://ws.agglayer.com'
  },
});

const core = coreOnlySDK.getCore();

Native-Only Setup (Blockchain Operations)

const nativeOnlySDK = new AggLayerSDK({
  mode: [SDK_MODES.NATIVE],
  native: {
    defaultNetwork: 1, // Ethereum Mainnet
    customRpcUrls: {
      1: 'https://eth-mainnet.g.alchemy.com/v2/your-key',
      137: 'https://polygon-mainnet.g.alchemy.com/v2/your-key',
    },
  },
});

const native = nativeOnlySDK.getNative();

Environment-Specific Configurations

// Development Configuration
const devConfig = {
  mode: [SDK_MODES.CORE, SDK_MODES.NATIVE],
  core: {
    apiBaseUrl: 'http://localhost:3001', // Local development server
    apiTimeout: 10000,
  },
  native: {
    defaultNetwork: 11155111, // Sepolia testnet
    customRpcUrls: {
      11155111: 'http://localhost:8545', // Local Ethereum fork
    },
  },
};

// Production Configuration
const prodConfig = {
  mode: [SDK_MODES.CORE, SDK_MODES.NATIVE],
  core: {
    apiBaseUrl: 'https://api.agglayer.com',
    apiTimeout: 30000,
  },
  native: {
    defaultNetwork: 1, // Ethereum Mainnet
    customRpcUrls: {
      1: process.env.ETHEREUM_RPC_URL,
      137: process.env.POLYGON_RPC_URL,
    },
  },
};

// Use environment-appropriate config
const config = process.env.NODE_ENV === 'production' ? prodConfig : devConfig;
const sdk = new AggLayerSDK(config);

Built-in Chain Registry

The SDK includes a comprehensive registry of popular networks:

  • Ethereum Mainnet (Chain ID: 1)
  • Katana (Chain ID: 747474)
  • Sepolia Testnet (Chain ID: 11155111)

Additional networks can be added via the chains configuration option.

🔧 Architecture & Design Principles

The SDK employs a modular microservice architecture with strict separation of concerns:

Core Module (SDK_MODES.CORE)

Core module primarily supports the features based on ARC API

  • Chain Registry: Comprehensive chain management
  • Route Discovery: Intelligently find routes for bridging, across agglayer bridge and other aggregators
  • Transaction Orchestration: Prepare unsigned executable transactions based on routes
  • Transactions Activity and History: Track status of transactions to perform aadditional functions like claim or view history of transactions.

Native Module (SDK_MODES.NATIVE)

Interact with blockchain and agglayer bridge directly, this does not involve any additional APIs(except for proof generation)

  • ERC20 Token Operations: Standards-compliant token interactions(getBalance, getAllowance, buildApprove, etc)
  • Bridge Infrastructure: Cross-chain asset transfer protocols (like bridgeTo, claimAsset, etc via ERC20 interface)

Key Design Principles

  • Type-First Development: 100% TypeScript with strict mode enabled
  • Flexible Configuration: Zero-config defaults with progressive customization
  • Immutable Data Structures: Predictable state management
  • Error-First Callbacks: Comprehensive error handling patterns
  • Smart Defaults: Intelligent fallbacks that work out-of-the-box
  • Modular Loading: Tree-shakeable imports for optimized bundles

� Release Channels & Versioning

The SDK follows semantic versioning with multiple release channels for different stability requirements:

Channel Description Stability Installation Use Case
latest Stable production releases ✅ Production Ready npm install @agglayer/sdk Production applications
beta Release candidates ⚠️ Testing npm install @agglayer/sdk@beta Pre-production testing
alpha Early feature previews 🚧 Experimental npm install @agglayer/sdk@alpha Feature development
dev Internal use 🔧 Development npm install @agglayer/sdk@dev SDK development & bleeding edge

Release Strategy

  • Stable releases (v1.0.0, v2.0.0): Thoroughly tested, API-stable versions
  • Beta releases (v1.0.0-beta.1): Feature-complete candidates with minimal changes expected
  • Alpha releases (v1.0.0-alpha.1): Early access to new features, API may change
  • Dev releases (v1.0.0-dev.1): Internal use

Quick Reference

Common Configuration Patterns

// Development with testnet
const devSdk = new AggLayerSDK({
  mode: [SDK_MODES.CORE, SDK_MODES.NATIVE],
  core: {
    apiBaseUrl: 'https://api-testnet.agglayer.com',
  },
  native: {
    defaultNetwork: 11155111, // Sepolia testnet
  },
});

// Production with custom timeouts
const prodSdk = new AggLayerSDK({
  core: {
    apiTimeout: 60000, // 60 second timeout
  },
});

// Multi-chain setup
const multiChainSdk = new AggLayerSDK({
  mode: [SDK_MODES.NATIVE],
  native: {
    defaultNetwork: 1,
    customRpcUrls: {
      1: 'https://ethereum-mainnet.infura.io/v3/YOUR_KEY',
      137: 'https://polygon-mainnet.infura.io/v3/YOUR_KEY',
      42161: 'https://arbitrum-mainnet.infura.io/v3/YOUR_KEY',
    },
  },
});

🔧 Development & Contributing

Prerequisites

  • Node.js 18+ or Bun 1.0+
  • TypeScript 4.9+
  • Git for version control

Local Development Setup

# Clone the repository
git clone https://github.com/agglayer/sdk.git
cd sdk

# Install dependencies (npm, yarn, or bun)
npm install
# or
bun install

# Build the project
npm run build

# Start development mode with hot reload
npm run dev

Available Development Scripts

Script Description Usage
npm run build Production build with optimizations CI/CD and release preparation
npm run dev Development build with watch mode Local development with hot reload
npm run typecheck TypeScript type checking without emit Validate types before commits
npm run test Run complete test suite Continuous testing during development
npm run test:run Single test run without watch CI/CD pipeline testing
npm run test:coverage Generate test coverage reports Quality assurance metrics
npm run test:watch Interactive test runner with file watching TDD development workflow
npm run lint ESLint code quality analysis Code style enforcement
npm run lint:fix Auto-fix ESLint issues Automated code style corrections
npm run format Prettier code formatting Consistent code style across codebase
npm run format:check Validate code formatting CI/CD formatting verification
npm run clean Remove build artifacts Clean slate rebuilds

🚨 Error Handling & Debugging

Comprehensive Error Types

The SDK provides detailed error information for all failure scenarios:

try {
  const routes = await core.getRoutes({
    fromChainId: 1,
    toChainId: 137,
    fromTokenAddress: '0xinvalid',
    toTokenAddress: '0x...',
    amount: '1000000000000000000',
    fromAddress: '0x...',
  });
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Input validation failed:', error.message);
    console.error('Field:', error.field);
    console.error('Value:', error.value);
  } else if (error instanceof NetworkError) {
    console.error('Network request failed:', error.message);
    console.error('Status:', error.status);
    console.error('Endpoint:', error.url);
  } else if (error instanceof ContractError) {
    console.error('Contract interaction failed:', error.message);
    console.error('Contract:', error.address);
    console.error('Function:', error.functionName);
  }
}

📈 Roadmap & Future Development

Upcoming Features

  • User input validations
  • Runtime api response validation using zod
  • WebSocket support for real-time updates of transactions and their status

Built with ❤️ by the AggLayer Team

⭐ Star us on GitHub🐛 Report Issues

About

Agglayer SDK — Unified Client Interface for Native and Aggregator Bridging

Resources

License

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •