Templates, Tutorials & Examples
Learn by building with production-ready templates and step-by-step guides
Seamlessly bridge assets and swap them for another token in a single transaction using Agglayer's unified bridge and call functionality.
Secure a unique username on one chain and automatically own it across all Agglayer-connected chains through bridge messaging.
Collateralize assets from one chain to borrow tokens on another, maximizing capital efficiency through Agglayer's Unified Bridge.
Liquidity positions between different protocols and chains while preserving exact parameters and unlocking enhanced yield opportunities.
Concepts
Learn by building with production-ready templates and step-by-step guides
Complete walkthrough of Agglayer architecture and ecosystem
Understanding cross-chain communication and bridge architecture
Security mechanisms and trust-minimized verification
How Agglayer ensures cross-chain integrity
Tools
Master the essential tools for building on Agglayer
Complete guide to using the JavaScript SDK
Local development, fork mode, and multi-L2 setup
Basic Token Transfer
Simple example of transferring tokens from one chain to another using the Agglayer bridge. This demonstrates the core bridge functionality with minimal configuration.
// Transfer tokens between chains using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
const transfer = await client.bridgeAsset({
originNetwork: 0, // Polygon
destinationNetwork: 1, // Arbitrum
token: '0xUSDC...',
amount: ethers.utils.parseUnits('1000', 6),
recipient: '0x123...',
forceUpdateGlobalExitRoot: true
});
console.log('Transfer ID:', transfer.transactionHash);
# Transfer tokens using aggsandbox CLI
aggsandbox bridge asset \
--network-id 0 \
--destination-network-id 1 \
--token-address 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 \
--amount 1000000000 \
--to-address 0x123... \
--private-key YOUR_PRIVATE_KEY
Check Multi-Chain Balance
Query token balances across all connected chains in the Agglayer network. Useful for displaying unified balance views in your dApp.
// Get balances across all chains using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Get balance on origin network
const balance = await client.getBalance({
userAddress: '0x123...',
token: '0xUSDC...',
network: 0 // Polygon
});
console.log(`Balance: ${ethers.utils.formatUnits(balance, 6)} USDC`);
# Check balance using aggsandbox CLI
# Note: aggsandbox focuses on bridging - use native chain tools for balance checks
cast balance 0x123... --rpc-url http://localhost:8545
# Or get ERC20 token balance
cast call 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 \
"balanceOf(address)(uint256)" 0x123... \
--rpc-url http://localhost:8545
Listen for Crosschain Events
Subscribe to real-time Crosschain events to track transfers and messages. Essential for building reactive interfaces that update when transfers complete.
// Subscribe to Crosschain events using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Listen for bridge events
client.on('bridgeEvent', (event) => {
console.log('Bridge event received:', {
from: event.originNetwork,
to: event.destinationNetwork,
amount: ethers.utils.formatUnits(event.amount, event.decimals),
token: event.tokenAddress
});
});
# Listen for Crosschain events using aggsandbox CLI
aggsandbox events \
--follow \
--network-id 0 \
--filter bridge
# Or show recent events
aggsandbox show bridges --network-id 0 --json
Batch Token Transfers
Execute multiple token transfers in a single transaction to save gas and improve efficiency. Ideal for applications that need to distribute tokens to multiple recipients.
// Execute multiple transfers using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Batch multiple bridge operations
const transfers = await Promise.all([
client.bridgeAsset({
originNetwork: 0,
destinationNetwork: 1,
token: '0xUSDC...',
amount: ethers.utils.parseUnits('1000', 6),
recipient: '0x123...'
}),
client.bridgeAsset({
originNetwork: 0,
destinationNetwork: 2,
token: '0xDAI...',
amount: ethers.utils.parseUnits('500', 18),
recipient: '0x456...'
})
]);
console.log('Transfer IDs:', transfers.map(t => t.transactionHash));
# Execute multiple transfers using aggsandbox CLI
# Transfer 1: USDC to network 1
aggsandbox bridge asset \
--network-id 0 \
--destination-network-id 1 \
--token-address 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 \
--amount 1000000000 \
--to-address 0x123... \
--private-key YOUR_PRIVATE_KEY
# Transfer 2: DAI to network 2
aggsandbox bridge asset \
--network-id 0 \
--destination-network-id 2 \
--token-address 0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063 \
--amount 500000000000000000000 \
--to-address 0x456... \
--private-key YOUR_PRIVATE_KEY
Bridge Custom Token
Bridge custom ERC20 tokens that aren't pre-configured in the system. Shows how to specify token details and handle non-standard tokens.
// Bridge a custom ERC20 token using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Bridge custom token with metadata
const customTransfer = await client.bridgeAsset({
originNetwork: 0,
destinationNetwork: 1,
token: '0xYourTokenAddress...',
amount: ethers.utils.parseUnits('1000', 18), // Custom decimals
recipient: '0x123...',
permitData: null, // No permit for custom tokens
forceUpdateGlobalExitRoot: true
});
console.log('Custom token bridge ID:', customTransfer.transactionHash);
// Bridge a custom ERC20 token using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Bridge custom token with metadata
const customTransfer = await client.bridgeAsset({
originNetwork: 0,
destinationNetwork: 1,
token: '0xYourTokenAddress...',
amount: ethers.utils.parseUnits('1000', 18), // Custom decimals
recipient: '0x123...',
permitData: null, // No permit for custom tokens
forceUpdateGlobalExitRoot: true
});
console.log('Custom token bridge ID:', customTransfer.transactionHash);
Send Crosschain Message
Send arbitrary data between smart contracts on different chains. Enables Crosschain contract interactions beyond simple token transfers.
// Send a message to another chain using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Prepare message data
const messageData = ethers.utils.defaultAbiCoder.encode(
['string', 'uint256'],
['Hello from Polygon!', 12345]
);
// Send Crosschain message
const message = await client.bridgeMessage({
destinationNetwork: 1, // Arbitrum
destinationAddress: '0xTargetContract...',
metadata: messageData,
forceUpdateGlobalExitRoot: true
});
console.log('Message sent:', message.transactionHash);
# Send Crosschain message using aggsandbox CLI
aggsandbox bridge message \
--network-id 0 \
--destination-network-id 1 \
--target 0xTargetContract... \
--data 0x48656c6c6f2066726f6d20506f6c79676f6e21 \
--private-key YOUR_PRIVATE_KEY
# Claim the message on destination
aggsandbox bridge claim \
--network-id 1 \
--tx-hash TX_HASH_FROM_BRIDGE \
--source-network-id 0
Add Liquidity Crosschain
Add liquidity to pools on other chains without leaving your current chain. Demonstrates Crosschain DeFi interactions with slippage protection.
// Add liquidity to a pool on another chain using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Bridge tokens and add liquidity in one transaction
const liquidityTx = await client.bridgeAsset({
originNetwork: 0, // Polygon
destinationNetwork: 1, // Arbitrum
token: '0xUSDC...',
amount: ethers.utils.parseUnits('1000', 6),
recipient: '0xPoolContract...', // DEX pool contract
metadata: ethers.utils.defaultAbiCoder.encode(
['uint256', 'uint256'],
[ethers.utils.parseUnits('1000', 6), ethers.utils.parseEther('0.5')] // USDC + ETH amounts
)
});
console.log('Liquidity bridge TX:', liquidityTx.transactionHash);
# Bridge-and-Call for DeFi interaction using aggsandbox CLI
aggsandbox bridge bridge-and-call \
--network-id 0 \
--destination-network-id 1 \
--token-address 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 \
--amount 1000000000 \
--target 0xPoolAddress... \
--data 0x... \
--private-key YOUR_PRIVATE_KEY
# Note: Use bridge-and-call for atomic bridge + contract execution
# Data should contain encoded function call for the target contract
Comprehensive Error Handling
Properly handle various error scenarios in Crosschain operations. Shows best practices for user-friendly error messages and recovery strategies.
// Handle various error scenarios with LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
try {
const transfer = await client.bridgeAsset({
originNetwork: 0,
destinationNetwork: 1,
token: '0xUSDC...',
amount: ethers.utils.parseUnits('1000', 6),
recipient: '0x123...'
});
} catch (error) {
if (error.code === 'INSUFFICIENT_BALANCE') {
console.error('Not enough tokens for bridge');
} else if (error.code === 'NETWORK_NOT_SUPPORTED') {
console.error('Destination network not supported');
} else if (error.code === 'GAS_ESTIMATION_FAILED') {
console.error('Cannot estimate gas cost');
} else if (error.message.includes('User denied')) {
console.error('Transaction rejected by user');
} else {
console.error('Unknown bridge error:', error);
}
}
# Handle errors with aggsandbox CLI
aggsandbox bridge asset \
--network-id 0 \
--destination-network-id 1 \
--token-address 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 \
--amount 1000000000 \
--to-address 0x123... \
--private-key YOUR_PRIVATE_KEY
# Check transaction status
aggsandbox show bridges --network-id 0 --json | jq '.bridges[0]'
# Check if claim is ready
aggsandbox show claims --network-id 1 --json
Gas Optimization Strategies
Optimize gas costs for Crosschain operations using batching, deadline settings, and priority levels. Essential for production applications.
// Optimize gas for Crosschain operations with LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Optimize bridge transaction
const optimizedTransfer = await client.bridgeAsset({
originNetwork: 0,
destinationNetwork: 1,
token: '0xUSDC...',
amount: ethers.utils.parseUnits('1000', 6),
recipient: '0x123...',
forceUpdateGlobalExitRoot: false, // Save gas by not forcing update
gasPrice: ethers.utils.parseUnits('20', 'gwei'), // Custom gas price
gasLimit: 150000 // Optimized gas limit
});
console.log('Optimized transfer:', optimizedTransfer.transactionHash);
# Bridge with gas optimization using aggsandbox CLI
aggsandbox bridge asset \
--network-id 0 \
--destination-network-id 1 \
--token-address 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 \
--amount 1000000000 \
--to-address 0x123... \
--private-key YOUR_PRIVATE_KEY \
--gas-price 20000000000
# Check current gas estimates
aggsandbox info | grep "Gas Price"
# Batch multiple operations by waiting before next transaction
Filter Crosschain Events
Filter Crosschain events by specific criteria like chain, token, or amount. Useful for monitoring specific types of transfers or building analytics.
// Filter events by criteria using LXLY.js
import { LxLyClient } from '@0xpolygonhermez/lxly-client';
const client = new LxLyClient({
network: 'testnet',
environment: 'browser'
});
// Filter bridge events with specific criteria
client.on('bridgeEvent', (event) => {
// Filter for large USDC transfers from Polygon to Arbitrum
if (event.originNetwork === 0 &&
event.destinationNetwork === 1 &&
event.tokenAddress.toLowerCase() === '0xusdc...' &&
ethers.utils.formatUnits(event.amount, 6) >= '100') {
console.log('Large USDC transfer detected:', {
amount: ethers.utils.formatUnits(event.amount, 6),
from: 'Polygon',
to: 'Arbitrum',
txHash: event.transactionHash
});
}
});
# Filter Crosschain events using aggsandbox CLI
aggsandbox show bridges --network-id 0 --json | \
jq '.bridges[] | select(.destination_network == 1 and .amount >= "100000000")'
# Show specific event types
aggsandbox events --network-id 0 --filter bridge
# Monitor claims on destination
aggsandbox show claims --network-id 1 --json | \
jq '.claims[] | select(.status == "COMPLETED")'