This guide will help you get familiar with LxLy.js, configure your code to interact with Agglayer chains, and bridge assets from the Ethereum Sepolia testnet to the Polygon zkEVM testnet using the Unified Bridge and lxly.js. In this guide you will:
- Configure your environment
- Bridge your asset
- Check its status using the Bridge API
- Use the claim API to claim the transaction on the destination chain.
Refer to this repository for complete code - Link
Before you begin, ensure that you have the following:
- Node.js & npm:
- Node.js: v14.0.0 or later
- npm: v6.0.0 or later
- Crypto Wallet:
A Crypto wallet (or similar) configured for testing. - Testnet ETH:
Acquire test ETH (from a faucet) for the Sepolia testnet.
Make sure your config.js
contains the correct network settings, RPC endpoints, bridge contract addresses, and account details. (See the Agglayer Unified Bridge repository for a sample configuration). The reference config.js
contains public rpc's as a placeholder , but it is recommended to get private rpc's for best results .
This file initializes your connection with the Unified Bridge using lxly.js. It configures network providers (using HDWalletProvider or similar) for both the source and destination networks.
Reference file - utils_lxly.js
const getLxLyClient = async (network = 'testnet') => {
const lxLyClient = new LxLyClient();
return await lxLyClient.init({
log: true,
network: network,
providers: {
// Source network: Sepolia Testnet (network ID: 0)
0: {
provider: new HDWalletProvider([config.user1.privateKey], config.configuration[0].rpc),
configuration: {
bridgeAddress: config.configuration[0].bridgeAddress,
bridgeExtensionAddress: config.configuration[0].bridgeExtensionAddress,
wrapperAddress: config.configuration[0].wrapperAddress,
isEIP1559Supported: true
},
defaultConfig: {
from: config.user1.address
}
},
// Destination network: Polygon zkEVM (network ID: 1)
1: {
provider: new HDWalletProvider([config.user1.privateKey], config.configuration[1].rpc),
configuration: {
bridgeAddress: config.configuration[1].bridgeAddress,
bridgeExtensionAddress: config.configuration[1].bridgeExtensionAddress,
isEIP1559Supported: false
},
defaultConfig: {
from: config.user1.address
}
},
}
});
}
In this step, you will initiate a cross-chain asset transfer from the Sepolia testnet to zkEVM (Agglayer).
What Happens:
- BRIDGED State:
When you call thebridgeAsset
API, the transaction is initiated on the source chain.
Script Walkthrough: bridge_asset.js
const { getLxLyClient, tokens } = require('./utils/utils_lxly');
const execute = async () => {
// Initialize the lxly client
const client = await getLxLyClient();
// Define source network ID (Sepolia Testnet)
const sourceNetworkId = 0;
// Get the API for the Ether token on the source network
const token = client.erc20(tokens[sourceNetworkId].ether, sourceNetworkId);
// Define destination network ID (zkEVM / Agglayer)
const destinationNetworkId = 1;
// Bridge a specific amount of Ether (in wei)
const result = await token.bridgeAsset("10000000000000000", config.user1.address, destinationNetworkId);
// Log the transaction hash and receipt
const txHash = await result.getTransactionHash();
console.log("txHash", txHash);
const receipt = await result.getReceipt();
console.log("receipt", receipt);
}
execute()
.then(() => {})
.catch(err => {
console.error("Error bridging asset:", err);
})
.finally(() => {
process.exit(0);
});
How to Run:
node bridge_asset.js
Before proceeding with claiming the asset, you need to verify its current status using the Transaction API. This step is typically performed using Postman or a cURL command.
- Testnet:
https://api-gateway.polygon.technology/api/v3/transactions/testnet?userAddress={userAddress}
- Mainnet:
https://api-gateway.polygon.technology/api/v3/transactions/mainnet?userAddress={userAddress}
Using Postman, import the API endpoint to check the status of your transaction. This query will return details such as the token bridged, the amount, and the current state of the transaction. Remember to get your API Key via this link.
After querying the Bridge API, you will receive information on the transaction states. The key states are:
-
BRIDGED:
The transaction has been initiated on the source chain (Sepolia) via thebridgeAsset
API. -
READY_TO_CLAIM:
The asset is now available on the destination chain (zkEVM / AggLayer) and is awaiting claim. -
CLAIMED:
The asset has been successfully claimed on the destination chain after using theclaimAsset
API.
These states are verified by querying the API (for example, via Postman).
Once the Bridge API shows that the asset is READY_TO_CLAIM, you can claim it on the destination chain using the claim API.
- CLAIMED State:
The asset moves from a pending state to claimed after executing the claim.
const { getLxLyClient, tokens } = require('./utils/utils_lxly');
const execute = async () => {
// Replace with your actual bridge transaction hash from the bridge_asset.js output
const bridgeTransactionHash = "0x1fc6858b20c75189a9fa8f3ae60c2a255cc3c41a058781f33daa57fc0f80b81a";
// Initialize the lxly client
const client = await getLxLyClient();
// Define source network ID (Sepolia Testnet)
const sourceNetworkId = 0;
// Define destination network ID (zkEVM / Agglayer)
const destinationNetworkId = 1;
// Get the API for the Ether token on the destination network
const token = client.erc20(tokens[destinationNetworkId].ether, destinationNetworkId);
// Claim the bridged asset using the claimAsset API
const result = await token.claimAsset(bridgeTransactionHash, sourceNetworkId, { returnTransaction: false });
console.log("Claim result:", result);
// Log the transaction hash and receipt for the claim transaction
const txHash = await result.getTransactionHash();
console.log("Claim txHash:", txHash);
const receipt = await result.getReceipt();
console.log("Claim receipt:", receipt);
}
execute()
.then(() => {})
.catch(err => {
console.error("Error claiming asset:", err);
});
How to run:
node claim_asset.js
After claiming the asset, verify the final state using the Bridge API: Use Postman or a curl command to ensure that the transaction state has been updated to CLAIMED.