# Overview Source: https://docs.polygon.technology/blockchain-rails/index The settlement layer for the Open Money Stack: Polygon Chain for public settlement and Polygon CDK for dedicated, compliance-grade infrastructure. Every component of the Open Money Stack depends on reliable settlement. The OMS offers two options depending on your requirements. ## Polygon Chain **Public, permissionless settlement.** Polygon Chain is the public Layer 2 network that serves as the default settlement layer for the OMS. It is open, permissionless, and production-proven at scale. * Sub-2-second finality * Average transaction cost of \$0.002 * \$54B in stablecoin transfer volume * 6.4B total transactions * 159M unique wallet addresses * Major integrations by Revolut, Stripe, Flutterwave, and more Polygon Chain is the right choice for applications that benefit from public auditability, open access, and the broadest possible ecosystem of tooling, liquidity, and users. Architecture, network stats, and how to start building on Polygon Chain. *** ## Polygon CDK **Dedicated, compliance-grade blockchain infrastructure.** For institutions that need their own rails, Polygon Chain Development Kit (CDK) lets you launch a production-ready rollup with custom throughput, fee structures, and compliance requirements. ### Why Polygon CDK * **20,000+ TPS** when optimized for payment workloads * **Rollup mode** with pessimistic proof security via Agglayer, validium, or full zkRollup * **Granular network control**: deploy as fully private or with gated access, API keys, and ACLs for read/write permissions * **EVM-equivalent**: deploy existing smart contracts without modification; standard Ethereum tooling works without reconfiguration * **Execution clients**: supports both op-geth and op-reth, giving operators flexibility in resource usage and performance tuning * **Implementation providers**: Conduit and Gateway are building open source tooling and support both execution clients for production deployments * **Migration paths**: zero-downtime migration for chains running Hyperledger Besu, preserving full data history ### Agglayer connectivity Cross-chain interoperability and unified liquidity are native features of every Polygon CDK chain. Agglayer provides shared state, cross-chain messaging, and trustless bridging across connected networks, without additional infrastructure. This means enterprise chains are not isolated: they can interoperate with Polygon Chain and other connected L2s from day one. ### Operating modes | Mode | Description | | ------------- | ----------------------------------------------------------------------------------------------- | | **Sovereign** | Agglayer connectivity secured by pessimistic proofs. No prover required. Default configuration. | | **Validium** | ZK-secured execution with offchain data availability via a DAC. | | **zkRollup** | Fully onchain zero-knowledge rollup for maximum security and Ethereum-aligned trust. | ### Who Polygon CDK is for * **Banks and financial institutions** needing dedicated settlement infrastructure with compliance controls and public auditability * **Asset issuers** that need custom compliance rules, token economics, or throughput requirements on dedicated chain infrastructure * **Enterprises and governments** building payment infrastructure that requires a sovereign rollup with full control over sequencing, fee policy, and data availability Explore Polygon CDK capabilities, operating modes, and how to get started. *** ## Choosing between them | | Polygon Chain | Polygon CDK | | -------------------- | ------------------------------------------- | --------------------------------------------------------------------------- | | **Access** | Public, permissionless | Private or gated | | **Throughput** | 110 TPS | 20,000+ TPS (payment-optimized) | | **Fee control** | Network-determined | Operator-defined | | **Compliance** | Application-level | Chain-level controls, ACLs, API keys | | **Infrastructure** | Shared public network | Dedicated rollup | | **Interoperability** | Native ecosystem access | Via Agglayer | | **Best for** | Open apps, broad reach, ecosystem liquidity | Regulated institutions, high-volume payment rails, sovereign infrastructure | Most applications start on Polygon Chain. Institutions with regulatory requirements, dedicated throughput needs, or custom fee structures deploy Polygon CDK chains that remain connected to the broader ecosystem via Agglayer. # Polygon CDK FAQs Source: https://docs.polygon.technology/chain-development/cdk/additional-resources/faqs Frequently asked questions about Polygon CDK, covering execution clients, rollup modes, and Agglayer integration. ## What is the Polygon CDK? Polygon Chain Development Kit (CDK) is a toolkit for launching Ethereum Layer 2 chains with native Agglayer connectivity. It supports **op-geth** and **op-reth** execution clients, giving operators flexibility in performance tuning and resource usage. ## What execution clients does CDK support? CDK supports two execution clients: * **op-geth**: Geth-based client with OP Stack architecture and broad tooling support. * **op-reth**: Reth-based client optimized for high throughput and lower resource consumption. Both are supported by Conduit and Gateway for production deployments. ## What is a sovereign chain in CDK? A sovereign chain operates without a prover. Instead, it uses pessimistic proofs via Agglayer to enforce safety and ensure that no chain can withdraw more than it deposits. This enables secure, low-cost execution with fast finality. Sovereign mode is the default configuration. ## What rollup modes are available? Every CDK chain supports three operating modes: * **Sovereign**: Agglayer connectivity secured by pessimistic proofs. No prover required. * **Validium**: ZK-secured execution with offchain data availability via a DAC. * **zkRollup**: Fully onchain ZK rollup for maximum security and Ethereum-aligned trust. ## How does Agglayer fit into Polygon CDK? Agglayer is a native feature of every CDK chain. It enables cross-chain interoperability, unified liquidity, and shared state across the connected network. CDK chains are connected to Agglayer by default. ## How can I start building with CDK? Use the CDK quickstarts to deploy a local testnet. For production-ready deployments, contact [**Conduit**](https://conduitxyz.typeform.com/to/CrvgqEeA?utm_source=polygonannouncement\&utm_medium=partnerblog) or [**Gateway**](https://share.hsforms.com/1toN701PtTBCpyc3bKQBCRAcy6wj?referrer=12118007123). # Glossary Source: https://docs.polygon.technology/chain-development/cdk/additional-resources/glossary Definitions of technical terms used throughout the Polygon CDK documentation. ### Agglayer Agglayer is a cross-chain settlement layer that connects the liquidity and users of any blockchain for fast, low-cost interoperability and growth. It enables trustless bridging, shared messaging, and unified state across Layer 2s using zero-knowledge (ZK) proofs. [Visit agglayer.dev](https://www.agglayer.dev/) ### Polygon CDK (Chain Development Kit) An enterprise-grade toolkit for building custom Ethereum Layer 2 chains. Each CDK chain is natively connected to Agglayer for cross-chain interoperability, shared liquidity, and integrated messaging. CDK supports **op-geth** and **op-reth** execution clients. ### Chain Operator An individual, team, or DAO responsible for launching and managing a CDK-based chain. Operators may handle sequencing, bridge operations, infrastructure deployment, data availability configuration, and other network responsibilities. ### Data Availability (DA) The requirement that transaction data remains accessible to Layer 1 validators for verifying off-chain execution. DA ensures the security of modular rollups. CDK chains can use onchain DA (e.g., Ethereum), off-chain DACs, or local solutions. ### Data Availability Committee (DAC) A decentralized set of nodes that ensures off-chain data availability for CDK chains using Validium mode. DAC nodes fetch transaction data, verify it, sign it, and store it for later retrieval. ### Implementation Providers (IPs) External infrastructure teams that assist developers with launching and maintaining CDK chains. Conduit and Gateway both support op-reth and op-geth execution clients and are building open source tooling for CDK deployments. ### Rollups Layer 2 solutions that execute transactions off-chain and post state data to Ethereum. CDK supports multiple rollup types, including: * [Optimistic rollups](https://ethereum.org/en/developers/docs/scaling/optimistic-rollups/) * [ZK rollups](https://ethereum.org/en/developers/docs/scaling/zk-rollups/) * Validium (ZK with off-chain DA) * Sovereign (non-ZK with pessimistic proofs) ### Sovereign Mode A rollup configuration that does not use a ZK prover. Instead, Agglayer enforces security through pessimistic proofs, ensuring that no chain can withdraw more than it deposits. Default configuration for CDK chains. ### Unified Bridge The shared bridge infrastructure for CDK chains, providing secure cross-chain asset transfers and messaging. It supports shared escrow, sovereign and ZK rollup flows, and native Agglayer integration. ### Unified Escrow A component of the Unified Bridge that holds tokens either bridged from Ethereum or minted natively on Layer 2. Ensures consistent accounting and solvency across all CDK chains. ### Validium A rollup configuration that uses ZK proofs for execution but stores transaction data off-chain, reducing costs and increasing throughput. CDK Validium chains rely on DACs for off-chain data availability. [Learn more about Validium](https://ethereum.org/en/developers/docs/scaling/validium/) ### ZK Proofs Zero-knowledge proofs validate computations without revealing input data. Agglayer uses ZK proofs to provide cryptographic guarantees for execution, enabling fast finality and trustless security across chains. # Deployment Modes Source: https://docs.polygon.technology/chain-development/cdk/cdk-opgeth/architecture Component reference for the three CDK deployment modes: sovereign, validium, and zkrollup. The three `cdk-opgeth` deployment modes differ primarily in data availability and prover setup. All share the same Geth-based client and OP Stack components. ### `cdk-opgeth-sovereign` CDK-opgeth Sovereign | Component | Description / Link | | ------------------------- | ------------------------------------------------------------------------------------------------------------------- | | Execution Layer | [OP Geth Client](https://github.com/ethereum-optimism/op-geth): Ethereum client modified for Optimism | | Consensus Layer | [OP Node](https://github.com/ethereum-optimism/optimism): Handles block production and synchronisation | | AggKit - Oracle | [AggOracle](https://github.com/agglayer/aggkit): Updates Global Exit Root (GER) onchain | | AggKit - Sender | Sends certificates from the chain to Agglayer | | Bridge API | [zkevm-bridge-service](https://github.com/0xPolygonHermez/zkevm-bridge-service): Enables messaging between chains | | Data Availability Layer | [OP Batcher](https://github.com/ethereum-optimism/optimism): Sends transaction data to Ethereum Mainnet (Layer 1) | | Agglayer Network | [Agglayer](https://github.com/agglayer/agglayer), Agglayer Node, Agglayer Prover | | Smart Contracts (L1 + L2) | [Optimism Contracts](https://github.com/ethereum-optimism/optimism/releases/tag/op-deployer%2Fv0.0.11) | | Ethereum Bridge Contracts | [Polygon zkEVM Contracts](https://github.com/0xPolygonHermez/zkevm-contracts): Manages final settlement on Ethereum | ### `cdk-opgeth-zkrollup` CDK-opgeth-zkrollup | Component | Description / Link | | ------------------------- | ------------------------------------------------------------------------------------------------------ | | Execution Layer | [OP Geth Client](https://github.com/ethereum-optimism/op-geth) | | Consensus Layer | [OP Node](https://github.com/ethereum-optimism/optimism) | | Proposer Service | [OP Proposer](https://github.com/ethereum-optimism/optimism) | | AggKit - Oracle | [AggOracle](https://github.com/agglayer/aggkit) | | AggKit - Sender | Sends certificates to Agglayer | | Bridge API | [zkevm-bridge-service](https://github.com/0xPolygonHermez/zkevm-bridge-service) | | Data Availability Layer | Ethereum Mainnet (onchain data only) | | Agglayer Network | [Agglayer](https://github.com/agglayer/agglayer), Agglayer Node, Agglayer Prover | | Smart Contracts (L1 + L2) | [Optimism Contracts](https://github.com/ethereum-optimism/optimism/releases/tag/op-deployer%2Fv0.0.11) | | Ethereum Bridge Contracts | [Polygon zkEVM Contracts](https://github.com/0xPolygonHermez/zkevm-contracts) | | Prover Network | [SP1 Prover](https://github.com/succinctlabs/sp1): zkVM-based prover | ### `cdk-opgeth-validium` This mode shares the same architecture as `zkrollup`, but uses an alternative data availability (DA) layer. | Component | Description / Link | | ------------------------- | ------------------------------------------------------------------------------------------------------------------- | | Execution Layer | [OP Geth Client](https://github.com/ethereum-optimism/op-geth) | | Consensus Layer | [OP Node](https://github.com/ethereum-optimism/optimism) | | Proposer Service | [OP Proposer](https://github.com/ethereum-optimism/optimism): Proposes blocks and batches | | AggKit - Oracle | [AggOracle](https://github.com/agglayer/aggkit) | | AggKit - Sender | Sends certificates to Agglayer | | Bridge API | [zkevm-bridge-service](https://github.com/0xPolygonHermez/zkevm-bridge-service) | | Data Availability Layer | [Alt-DA Mode (TBD)](https://docs.optimism.io/stack/beta-features/alt-da-mode): Off-chain or alternative DA provider | | Agglayer Network | [Agglayer](https://github.com/agglayer/agglayer), Agglayer Node, Agglayer Prover | | Smart Contracts (L1 + L2) | [Optimism Contracts](https://github.com/ethereum-optimism/optimism/releases/tag/op-deployer%2Fv0.0.11) | | Ethereum Bridge Contracts | [Polygon zkEVM Contracts](https://github.com/0xPolygonHermez/zkevm-contracts) | | Prover Network | [SP1 Prover](https://github.com/succinctlabs/sp1): zkVM-based prover | # Devnet Deployment Guide Source: https://docs.polygon.technology/chain-development/cdk/cdk-opgeth/devnet-deployment-guide How to deploy a production-like Pessimistic Proof (cdk-opgeth-sovereign) devnet. Use this guide to deploy a production-like **Pessimistic Proof (PP)** (`cdk-opgeth-sovereign`) devnet. *** ## Prerequisites Before starting, ensure you have: * A valid L1 RPC URL * A wallet address with Sepolia testnet funds (deployer) * [Docker](https://www.docker.com/) (or any other container orchestrator of your choice) * [Cast](https://book.getfoundry.sh/cast/) * [Polycli](https://github.com/0xPolygon/polygon-cli) * [Reference Repo](https://github.com/0xPolygon/cdk-devnets/tree/main/cdk-opgeth-pp) (configuration files used in the guide) Export these variables: ```bash theme={null} export L1_RPC_URL=https://... export SEPOLIA_PROVIDER=${L1_RPC_URL} export DEPLOYER_PRIVATE_KEY=0x0000000000000000000000000000000000000000 ``` The values shown are specific to this example. Replace them with values relevant to your own setup. *** ## Rollup Network Creation ### Step 1: Submit a Request To initiate the rollup creation: 1. The **Implementation Provider (IP)** must submit a request to Polygon Labs. 2. Use the [Polygon Support Portal](https://polygon.atlassian.net/servicedesk/customer/portal/22) to raise a support ticket. #### Required Parameters | Parameter | Description | Example | | ----------------- | --------------------------------------------- | -------------------------------------------- | | Rollup Type | Type of rollup | `Pessimistic Proofs (PP)` | | Chain ID | Unique identifier for your rollup | `473` | | Admin Address | Your control address for rollup modifications | `0xBe46896822BD1d415522F3a5629Fe28447b95563` | | Sequencer Address | Used by AggKit, must be under your control | `0x0769fcb9ca9369b0494567038E5d1f27f0CBE0aC` | | Gas Token Address | Token or zero address | `0x0000000000000000000000000000000000000000` | | Sequencer URL | *(Not used for PP)* | `https://...` | | Datastream URL | *(Not used for OP)* | `https://...` | | Network Name | Final network name (non-editable) | `bali-36-op` | *** ### Step 2: Setup by Polygon Labs Once approved: * Polygon Labs provisions your Rollup. * A transaction is recorded (e.g., [example](https://sepolia.etherscan.io/tx/0x111618eedb16b416aef393db6dd2d73d5a190dd5e15bdaa704473ba89a497f92)). You will receive: * `combined.json`: Core deployment details * `genesis-base.json`: Needed for genesis generation Store these files securely. They are required for further deployment steps. *** ## Genesis File Generation ### Option Selection Choose one: * **Option 1 (Recommended)**: Merge OP + Polygon Genesis with pre-deployed contracts. * **Option 2**: Manual L2 contract deployment. This guide focuses on **Option 1**. *** ### Step-by-Step Instructions 1. **Environment Setup** Checkout the Desired Version. We will be using`v10.0.0-rc.7` in this example ```bash theme={null} git clone https://github.com/0xPolygonHermez/zkevm-contracts.git cd zkevm-contracts git checkout v10.0.0-rc.7 ``` Install dependencies as described in the repo's [README](https://github.com/0xPolygonHermez/zkevm-contracts). 2. **Parameter File Creation** ```bash theme={null} cp ./tools/createSovereignGenesis/create-genesis-sovereign-params.json.example ./tools/createSovereignGenesis/create-genesis-sovereign-params.json ``` Update this file with the relevant information from your `combined.json` and your wallet addresses. ```json theme={null} { "rollupManagerAddress": "polygonRollupManagerAddress", "rollupID": rollupID, "chainID": chainID, "gasTokenAddress": "gasTokenAddress", "bridgeManager": "admin address", "sovereignWETHAddress": "0x0000000000000000000000000000000000000000", "sovereignWETHAddressIsNotMintable": false, "globalExitRootUpdater": "aggoracle address", "globalExitRootRemover": "0x0000000000000000000000000000000000000000", "emergencyBridgePauser": "admin address", "setPreMintAccounts": true, "preMintAccounts": [ # add as many as you like { "balance": "1000000000000000000", "address": "admin address" } ], "setTimelockParameters": true, "timelockParameters": { "adminAddress": "admin address", "minDelay": 0 # timelock delay, for devnets it's convinient to set it to zero }, "formatGenesis": "geth" } ``` 3. **Base Genesis Template** ```bash theme={null} cp ./tools/createSovereignGenesis/genesis-base.json.example ./tools/createSovereignGenesis/genesis-base.json ``` Paste the contents of your `genesis-base.json` into this file. 4. **Generate Genesis Files** ```bash theme={null} npx hardhat run ./tools/createSovereignGenesis/create-sovereign-genesis.ts --network sepolia ``` 5. **Rename the Output Files for Clarity** ```bash theme={null} mv ./tools/createSovereignGenesis/genesis-rollupID-*.json ./tools/createSovereignGenesis/polygon-genesis.json mv ./tools/createSovereignGenesis/output-rollupID-*.json ./tools/createSovereignGenesis/polygon-genesis-info.json ``` *** ## Network Deployment ### Environment Variables ```bash theme={null} export CLAIMTX_ADDRESS=0x0e40237b464f9945FDE774a2582109Aa943b9111 export AGGORACLE_ADDRESS=0x94e8844309E40f4FFa9146a7a890077561f925bc export CHAIN_ID=473 ``` The values shown are specific to this example. Replace them with values relevant to your own setup. ### L2 Deployment (Using op-deployer) To set up your Layer 2 (L2) network using the OP Stack, we recommend starting with the [official Optimism L2 Rollup tutorial](https://docs.optimism.io/operators/chain-operators/tutorials/create-l2-rollup). This guide provides a practical reference based on that tutorial and uses the [op-deployer](https://docs.optimism.io/operators/chain-operators/tools/op-deployer) tool to streamline the deployment process. All commands in this section are executed from the root directory of your project. 1. **Initialize deployer Folder** ```bash theme={null} docker run --rm -v $(pwd)/deployer:/deployer -it us-docker.pkg.dev/oplabs-tools-artifacts/images/op-deployer:v0.0.13 \ init \ --l1-chain-id 11155111 \ --l2-chain-ids "${CHAIN_ID}" \ --workdir /deployer ``` 2. **Edit `intent.toml`** with your parameters. 3. **Deploy L1 Contracts** ```bash theme={null} docker run --rm -v $(pwd)/deployer:/deployer -it us-docker.pkg.dev/oplabs-tools-artifacts/images/op-deployer:v0.0.13 \ apply \ --workdir /deployer \ --l1-rpc-url ${L1_RPC_URL} \ --private-key ${DEPLOYER_PRIVATE_KEY} ``` 4. **Merge Genesis Files** Next, you'll need to combine the `polygon-genesis.json` file with the OP Stack's `genesis.json`. The recommended approach is to embed the contents of `polygon-genesis.json` directly into the op-deployer state. ```bash theme={null} # extract the allocs cat deployer/state.json | jq -r '.opChainDeployments[].allocs' | base64 -d | gzip -d > allocs.json # merge jq -s add allocs.json files/polygon-genesis.json | gzip | base64 > merge # create a copy of the original state cp deployer/state.json deployer/original-state.json # replace the original allocs by the merged cat deployer/state.json | jq ".opChainDeployments[].allocs=\"$( cat merge )\"" > state.json && mv state.json deployer/state.json # cleanup rm allocs.json merge ``` 5. **Generate Files** ```bash theme={null} docker run --rm -v $(pwd)/deployer:/deployer -it us-docker.pkg.dev/oplabs-tools-artifacts/images/op-deployer:v0.0.13 \ inspect genesis \ --workdir /deployer "${CHAIN_ID}" > ./deployer/genesis.json docker run --rm -v $(pwd)/deployer:/deployer -it us-docker.pkg.dev/oplabs-tools-artifacts/images/op-deployer:v0.0.13 \ inspect rollup \ --workdir /deployer "${CHAIN_ID}" > ./deployer/rollup.json ``` *** ## Component Setup ### OP Stack 1. **Create `.env` values** ```bash theme={null} CHAIN_ID=473 SEQUENCER_PRIVATE_KEY=redacted BATCHER_PRIVATE_KEY=redacted L1_RPC_URL_HTTP=https://... L1_RPC_URL_WS=wss://... ``` The values shown are specific to this example. Replace them with values relevant to your own setup. 2. **Generate secret** ```bash theme={null} openssl rand -hex 32 > deployer/jwt.txt ``` 3. **Fund the batcher wallet on L1** 4. **Initialize Data Directory** ```bash theme={null} docker run --rm -it \ -v $(pwd)/deployer/genesis.json:/etc/optimism/genesis.json:ro \ -v $(pwd)/datadir:/datadir \ us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101411.3 \ init \ --state.scheme=hash \ --datadir=/datadir \ /etc/optimism/genesis.json ``` 5. **Start Services** ```bash theme={null} docker compose up -d op-geth docker compose up -d op-node docker compose up -d op-batcher ``` *** ### Aggkit 1. **Config** Update the `config/aggkit.toml` and `config/bridge.toml` config files with the relevant information from your `combined.json`, `polygon-genesis-info.json` and your wallet addresses. 2. **Create keystore files** The aggkit and bridge services require the sequencer, aggoracle, and claimtx wallet addresses to be provided through an encrypted keystore. ```bash theme={null} mkdir keystore cast wallet import --private-key ${SEQUENCER_PRIVATE_KEY} --keystore-dir .keystore/ sequencer.keystore cast wallet import --private-key ${AGGORACLE_PRIVATE_KEY} --keystore-dir .keystore/ aggoracle.keystore cast wallet import --private-key ${CLAIMTX_PRIVATE_KEY} --keystore-dir .keystore/ claimtx.keystore ``` 3. **Fund ClaimTX & Aggoracle** ```bash theme={null} cast send \ --value 100ether \ --mnemonic "test test test test test test test test test test test junk" \ --rpc-url http://$(docker compose port op-geth 8545) \ "${CLAIMTX_ADDRESS}" cast send \ --value 10ether \ --mnemonic "test test test test test test test test test test test junk" \ --rpc-url http://$(docker compose port op-geth 8545) \ ${AGGORACLE_ADDRESS} ``` 4. **Start PostgreSQL DB** ```bash theme={null} docker compose up -d db ``` 5. **Run Services** ```bash theme={null} docker compose up -d bridge docker compose up -d aggkit ``` *** ## Bridge ### Environment Variables ```bash theme={null} export ROLLUP_ID=36 export BRIDGE_ADDRESS=0x1348947e282138d8f377b467f7d9c2eb0f335d1f export TEST_ADDRESS=0xda9f3DCA867C4Bc7b1f8e2DB47Aa8C338Ba2e056 export TEST_PRIVATE_KEY=redacted ``` The values shown are specific to this example. Replace them with values relevant to your own setup. ### L1 to L2 1. **Initiate the Deposit from L1** Use the following command to bridge assets from L1 to your L2 network: ```bash theme={null} polycli ulxly bridge asset \ --bridge-address ${BRIDGE_ADDRESS} \ --destination-network ${ROLLUP_ID} \ --private-key ${TEST_PRIVATE_KEY} \ --rpc-url ${L1_RPC_URL} \ --value $(cast to-wei 0.1) ``` 2. **Verify the Deposit on L2** Once the deposit is claimed on L2, you can verify it by checking the balance of the target address: ```bash theme={null} cast balance ${TEST_ADDRESS} --ether --rpc-url=http://$(docker compose port op-geth 8545) ``` ### L2 to L1 1. **Initiate a Deposit** Start by making a deposit from L2 using the following command: ```bash theme={null} polycli ulxly bridge asset \ --bridge-address ${BRIDGE_ADDRESS} \ --destination-network 0 \ --private-key ${TEST_PRIVATE_KEY} \ --rpc-url http://$(docker compose port op-geth 8545) \ --value $(date +%s) \ --destination-address ${TEST_ADDRESS} ``` 2. **Wait for the Pessimistic Proof** Once the deposit is made, a pessimistic proof will be generated. After this proof is available, the deposit becomes eligible for claiming. 3. **Verify the Deposit Status** You can check the status of your deposit by querying the bridge service: ```bash theme={null} curl -s http://$(docker compose port bridge 8080)/bridges/${TEST_ADDRESS} | jq '.' { "deposits": [ { "leaf_type": 0, "orig_net": 0, "orig_addr": "0x0000000000000000000000000000000000000000", "amount": "1746047601", "dest_net": 0, "dest_addr": "0xda9f3DCA867C4Bc7b1f8e2DB47Aa8C338Ba2e056", "block_num": "14136", "deposit_cnt": 0, "network_id": 36, "tx_hash": "0x4a5d4914e4ae315af941e1fad2b2aac54dfd6c9bc2ca6033e0ea0b325fbcd90e", "claim_tx_hash": "", "metadata": "0x", "ready_for_claim": true, "global_index": "150323855360" } ], "total_cnt": "1" } ``` If `"ready_for_claim": true`, the deposit is ready to be claimed. 4. Claim the Deposit on L1 Run the following command to claim the deposit: ```bash theme={null} polycli ulxly claim asset \ --bridge-address ${BRIDGE_ADDRESS} \ --bridge-service-url http://$(docker compose port bridge 8080) \ --deposit-count 0 \ --destination-address ${TEST_ADDRESS} \ --deposit-network ${ROLLUP_ID} \ --private-key ${TEST_PRIVATE_KEY} \ --rpc-url ${L1_RPC_URL} ``` 5. Confirm the Claim Finally, confirm that the deposit has been successfully claimed by checking the balance of the destination address: ```bash theme={null} cast balance ${TEST_ADDRESS} --ether --rpc-url=${L1_RPC_URL} ``` *** Your PP network is now live. # Going to Production Source: https://docs.polygon.technology/chain-development/cdk/cdk-opgeth/going-to-production Deploy a CDK chain to testnet or mainnet with support from implementation providers. ## Overview Moving from a local devnet to a production CDK chain on testnet or mainnet requires infrastructure planning, bridge configuration, and AggLayer registration. Polygon's implementation providers handle this process end-to-end. ## Implementation providers Two providers currently support production CDK deployments: | Provider | Execution clients | What they handle | | ----------------------------------------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------ | | [**Conduit**](https://conduitxyz.typeform.com/to/CrvgqEeA?utm_source=polygonannouncement\&utm_medium=partnerblog) | op-geth, op-reth | Full chain deployment, infrastructure management, monitoring, and ongoing operations | | [**Gateway**](https://share.hsforms.com/1toN701PtTBCpyc3bKQBCRAcy6wj?referrer=12118007123) | op-geth, op-reth | Chain deployment, custom configurations, and managed infrastructure | Both providers support all three [deployment modes](/chain-development/cdk/cdk-opgeth/architecture/): sovereign, validium, and zkrollup. ## Testnet deployment Testnet deployments let you validate your chain configuration, bridge behavior, and application integrations before going to mainnet. Contact an implementation provider to set up a testnet environment. They will provision: * L1 and L2 node infrastructure * Bridge service and AggKit components * AggLayer connectivity (testnet) * Monitoring and alerting ## Mainnet deployment Mainnet deployment follows the same process as testnet with additional requirements: * **AggLayer registration:** Your chain must be registered with AggLayer through the [Polygon Support Portal](https://polygon.atlassian.net/servicedesk/customer/portal/22). * **Bridge contract deployment:** L1 bridge contracts are deployed and verified on Ethereum mainnet. * **Safe Proposer setup:** Rollup registration uses a Safe multisig proposer for governance. Your implementation provider coordinates these steps as part of the deployment process. ## Self-operated chains If you prefer to operate your own infrastructure, start with the [Quickstart](/chain-development/cdk/cdk-opgeth/local-guide/) and [Devnet Deployment Guide](/chain-development/cdk/cdk-opgeth/devnet-deployment-guide/) to understand the component architecture. For production self-operation, contact the Polygon team through the [Support Portal](https://polygon.atlassian.net/servicedesk/customer/portal/22) to discuss requirements. # Quickstart Source: https://docs.polygon.technology/chain-development/cdk/cdk-opgeth/local-guide How to deploy a local cdk-opgeth testnet using Kurtosis, including L1, L2, Agglayer, and OP Stack components. Use this guide to deploy a local testnet instance of `cdk-opgeth` using Kurtosis. This includes a local L1 + L2 environment with Agglayer components and OP Stack infrastructure. *** ## 1. Install Kurtosis Follow the installation instructions from the [Kurtosis official docs](https://docs.kurtosis.com/install). *** ## 2. Launch the cdk-opgeth Stack Use the command below to run the Kurtosis package: ```bash theme={null} kurtosis run \ --enclave cdk \ --args-file https://raw.githubusercontent.com/0xPolygon/kurtosis-cdk/refs/tags/v0.4.0/.github/tests/chains/op-succinct.yml \ github.com/0xPolygon/kurtosis-cdk@v0.4.0 ``` This will: * Start an L1 devnet (Ethereum-like chain) * Deploy Agglayer common contracts * Deploy op-geth, op-node, and op-batcher * Deploy Aggkit and op-succinct infrastructure Kurtosis service output *** ## 3. Bridge Funds from L1 to L2 Use `polycli` to bridge assets from L1 to L2: ```bash theme={null} polycli ulxly bridge asset \ --bridge-address $(kurtosis service exec cdk contracts-001 'jq -r '.polygonZkEVMBridgeAddress' /opt/zkevm/combined.json') \ --private-key 0x12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ --destination-address 0x9175f8176014543492234099F37a385335a017d6 \ --destination-network 1 \ --value 1000000000000000000 \ --rpc-url http://$(kurtosis port print cdk el-1-geth-lighthouse rpc) ``` Kurtosis service output *** **Command parameters:** * `polycli ulxly bridge asset`: Initiates the bridge * `--bridge-address`: Reads from `combined.json` * `--private-key`: Specifies the sender wallet * `--destination-address`: L2 recipient * `--destination-network`: Target network ID (1 for devnet) * `--value`: Amount to bridge in wei * `--rpc-url`: Dynamically resolved RPC from Kurtosis A successful call returns a transaction confirmation. Kurtosis service output *** ## 4. Check Balance on L2 ```bash theme={null} cast balance --ether \ --rpc-url $(kurtosis port print cdk op-el-1-op-geth-op-node-001 rpc) \ 0x9175f8176014543492234099F37a385335a017d6 ``` Kurtosis service output *** ## 5. Send a Transaction on L2 (Inscription) ```bash theme={null} cast send \ --rpc-url $(kurtosis port print cdk op-el-1-op-geth-op-node-001 rpc) \ --private-key 0xfa5f1cc57271a4ccbc5f0becd6bbca6a542973fa2b323d918c5e625fb67bdb20 \ 0x9175f8176014543492234099F37a385335a017d6 \ $(echo -n 'data:,Hello Agglayer!' | xxd -p) ``` This command sends a transaction with `Hello Agglayer!` embedded in the calldata. Kurtosis service output *** ## 6. View the Inscription ```bash theme={null} cast tx \ --rpc-url $(kurtosis port print cdk op-el-1-op-geth-op-node-001 rpc) \ 0x2ec6e2097ef85360cdb1fde9d711412c4ce304a79da5afa69ef9abdbebd6757e input | \ xxd -r -p ``` Expected output: ```bash theme={null} data:,Hello Agglayer! ``` # Why Choose CDK? Source: https://docs.polygon.technology/chain-development/cdk/get-started/benefits Key benefits of Polygon CDK, including EVM compatibility, Agglayer integration, rollup modes, and implementation support. ## EVM Compatibility Chains built with the Polygon Chain Development Kit (CDK) are fully EVM-equivalent. Existing smart contracts can be deployed without modification, and standard Ethereum tooling works without reconfiguration. ## Performance * 60 to 100+ Mgas/s throughput * 20,000+ TPS when optimized for payment workloads * Sub-60-minute finality in zkRollup and validium modes CDK supports two execution clients: **op-geth** (Geth-based) and **op-reth** (Reth-based), giving operators flexibility in resource usage and performance tuning. ## Rollup Modes Every CDK chain supports multiple rollup modes: * **Sovereign**: No ZK prover required. Agglayer enforces security through pessimistic proofs. Default configuration. * **Validium**: ZK-secured execution with offchain data availability. Lower cost and higher throughput than zkRollup. * **zkRollup**: Fully onchain ZK rollup. Maximum security and Ethereum-aligned trust assumptions. Operators select the mode that best balances cost, trust assumptions, and data availability for their use case. ## Agglayer Integration All CDK chains connect to **Agglayer** by default. Cross-chain interoperability, unified liquidity, and shared state are native features of every enterprise chain, not add-ons that require additional infrastructure. ## Implementation Providers For production deployments, CDK chains are typically launched with the support of an implementation provider: * **Conduit** and **Gateway** both support **op-reth** and **op-geth** execution clients. * Both providers are building open source tooling for CDK deployments. Review common questions about execution clients, Agglayer integration, and deployment paths. Contact Polygon about a dedicated enterprise chain and managed deployment support. # What is CDK? Source: https://docs.polygon.technology/chain-development/cdk/get-started/overview Enterprise-grade toolkit for building custom Ethereum L2 chains. Agglayer interoperability is built in by default. The Polygon Chain Development Kit (CDK) is an enterprise-grade toolkit for building custom Ethereum Layer 2 (L2) chains. Every CDK chain connects to **Agglayer** by default — cross-chain interoperability, shared liquidity, and unified state are native features of the infrastructure, not optional add-ons. ## Execution clients CDK supports two execution clients, both maintained as open source by implementation providers: * **op-geth**: Geth-based client with OP Stack architecture. Familiar developer environment and broad tooling support. * **op-reth**: Reth-based client optimized for high throughput and lower resource consumption. Both clients are supported by **Conduit** and **Gateway**, who are building open source tooling for production CDK deployments. ## Performance * 60 to 100+ million gas per second (Mgas/s) * Over 4,700 peak TPS in standard configuration * **20,000+ TPS** when optimized for payment workloads * Finality in under 60 minutes in zkRollup and validium modes ## Rollup modes Every CDK chain supports three operating modes: | Mode | Status | Description | | ------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Sovereign** | Live | Agglayer connectivity secured by pessimistic proofs. No prover required. Default configuration. | | **Validium** | Live | ZK-secured execution with offchain data availability. Available today via OP Succinct AltDA; see [Privacy Configuration](/chain-development/cdk/privacy). | | **zkRollup** | In development | Fully onchain ZK rollup for maximum security and Ethereum-aligned trust. | ## Agglayer integration All CDK chains connect to Agglayer by default. This provides unified liquidity, shared state, and cross-chain messaging as a native feature of every enterprise chain, without additional bridging infrastructure. ## Projects using CDK * Ternoa * Merlin Chain * Magic Labs (Newton) * Silicon Network * Witness Chain * WireX * Lumia (formerly Orion) * Okto Wallet * Palm Network * Prom * OKX * Moonveil *...and more* Compare execution clients, operating modes, and implementation options. Contact Polygon about a dedicated enterprise chain and managed deployment support. # Overview Source: https://docs.polygon.technology/chain-development/cdk/index Deploy your own custom blockchain with built-in Agglayer interoperability. Enterprise-grade rollup infrastructure for payments, compliance, and dedicated chain rails. Polygon CDK Polygon Chain Development Kit (CDK) lets institutions deploy their own custom blockchain on production-ready rollup infrastructure. Every CDK chain connects to **Agglayer** by default, so cross-chain interoperability and unified liquidity are built into the infrastructure from day one — not a separate integration. CDK provides enterprise-grade blockspace with predictable costs, privacy options, performance under load, and uptime guarantees, purpose-built for institutions that need compliance controls without sacrificing connectivity. ## Key capabilities Every CDK chain connects to Agglayer by default. Cross-chain asset transfers and unified liquidity are native features — no additional bridging infrastructure required. 20,000+ TPS when optimized for payment workloads. 100+ Mgas/s throughput. Managed uptime SLA with lower maintenance complexity compared to Hyperledger Besu setups. Deploy as fully private or with gated access and offchain data. API keys and access control lists let you filter read/write permissions and specific contract or RPC method calls. Migration pathways for chains running Besu, preserving full data history without business disruption. ## Operating modes | Mode | Description | | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Sovereign** | Agglayer connectivity secured by pessimistic proofs. No prover required. Default configuration. | | **Validium** | ZK-secured execution with offchain data availability. Available today via OP Succinct AltDA; see [Privacy Configuration](/chain-development/cdk/privacy). | | **zkRollup** | Fully onchain zero-knowledge rollup for maximum security and Ethereum-aligned trust. | ## Get started Review the architecture, execution stacks, and rollup modes before planning a deployment. Contact Polygon about a dedicated enterprise chain and managed deployment support. ## Resources Architecture, execution stacks, and technical capabilities. Key benefits and why enterprises choose CDK over alternatives. Frequently asked questions from developers and infrastructure providers. Polygon CDK product overview on agglayer.dev. # Privacy Configuration Source: https://docs.polygon.technology/chain-development/cdk/privacy Deploy a private Polygon CDK chain where transaction data stays in your infrastructure and Ethereum settles a validity proof. Built on OP Succinct AltDA. Polygon CDK supports a privacy configuration for institutions that need to keep transaction data inside their own infrastructure while retaining Ethereum-anchored security and Agglayer interoperability. The chain runs as an OP Stack validium: raw transaction data is held in a data availability server the institution operates, and Ethereum sees only a Keccak256 commitment plus a SP1 Hypercube validity proof. This configuration is intended for regulated institutions that want full control over where customer data lives while staying connected to the broader Ethereum ecosystem for liquidity and settlement. ## Stack At A Glance The privacy configuration runs OP Stack in OP Succinct validium mode, with [SP1 Hypercube](https://blog.succinct.xyz/op-succinct-data-confidentiality/) handling proof generation and AltDA serving as the institution-operated data availability layer. Implementation partners like [Conduit](https://conduit.xyz) and [Gateway](https://gateway.fm) operate the stack as a service; institutions can also run sequencers themselves. The chain settles to Ethereum and connects to Agglayer for cross-chain liquidity and state. ## What This Configuration Delivers **Customer data confidentiality.** Sensitive transaction data stays inside infrastructure the institution owns and operates. Regulators, auditors, and counterparties receive scoped access on the institution's terms. **Self-hosted infrastructure.** Data availability runs behind the institution's existing security perimeter, in jurisdictions it has already cleared with compliance. There is no third-party dependency for data storage or retrieval. **Global liquidity.** The chain stays connected to the Ethereum ecosystem through Agglayer, retaining access to stablecoins, tokenized assets, and counterparty capital across connected chains. **Ethereum-anchored security.** Every chain transition is verified by a ZK validity proof settled to Ethereum, inheriting Ethereum's economic security for settlement. ## How It Works The privacy configuration replaces the OP Stack's default L1 data availability with a Keccak256-commitment alt-DA flow. The pipeline runs in four stages: 1. **Batch submission to private DA.** When the sequencer produces a batch, `op-batcher` submits the batch data to the institution's data availability server using the standard OP Stack alt-DA HTTP API. `PUT /put` returns a Keccak256 commitment; `GET /get/0x{commitment}` retrieves the data. 2. **L1 anchoring.** The batcher posts an L1 transaction containing the `DerivationVersion1` prefix byte (`0x01`) followed by the 32-byte Keccak256 commitment. Raw transaction data never reaches a public network. 3. **Proof generation.** The OP Succinct proposer reads the L1 commitment, fetches the batch data from the DA server, and feeds it to SP1. Inside the zkVM, the proving program verifies `keccak256(data) == commitment` via the preimage oracle before executing the OP Stack derivation pipeline. 4. **Proof settlement.** The validity proof is posted to the chain's `OPSuccinctL2OutputOracle` contract on Ethereum, where it is verified against a range verification key and rollup config hash pinned at deployment. ```mermaid theme={null} sequenceDiagram participant Batcher as op-batcher participant DA as Private DA server participant L1 as Ethereum L1 participant Proposer as op-proposer participant SP1 as SP1 zkVM participant Oracle as L2 Output Oracle Batcher->>DA: PUT /put (batch data) DA-->>Batcher: Keccak256 commitment Batcher->>L1: post 0x01 prefix + commitment Proposer->>L1: read commitment Proposer->>DA: GET /get/0x{commitment} DA-->>Proposer: batch data Proposer->>SP1: verify keccak256(data)==commitment, derive SP1-->>Proposer: validity proof Proposer->>Oracle: submit proof Oracle->>Oracle: verify against pinned VK ``` ## Trust Model The privacy configuration splits trust between data integrity and data availability: * **Data integrity is not trusted to the DA server.** SP1 verifies `keccak256(data) == commitment` inside the zkVM before accepting any data into the derivation pipeline. A malicious or compromised DA server cannot forge state. * **Data availability is trusted to the DA server.** If the DA server loses data or refuses to serve it for a given commitment, no proof can be produced for the affected range. DA-layer redundancy, backup, and access control are the operator's responsibility. For institutional deployments this is the intended trust split: the DA server sits inside the operator's perimeter precisely so the operator controls availability. Cryptographic integrity is enforced by the prover; operational availability is enforced by the institution's own infrastructure practices. ## Access Control The privacy configuration is typically paired with chain-level access controls. These are operator-configurable surfaces; some require additional implementation by the operator or the rollup-as-a-service partner: * **Gated RPC endpoints.** Custom RPC layers can be placed behind enterprise identity systems such as Okta, Azure AD, or any OIDC-compatible SSO. * **Permissioned block explorers.** Block-explorer access can be restricted to authorized users. * **Custom sequencer policies.** Sequencers can enforce KYC-gated mempools, allowlists, and other admission policies. * **Contract-level access controls.** Application logic can enforce per-function and per-role access controls within each smart contract. ## Configuration Reference The AltDA configuration is gated behind a Cargo feature and a single required environment variable: * **Feature flag:** `altda` Cargo feature on the `validity` binary. * **Environment variable:** `ALTDA_SERVER_URL` (no default; the deployment fails to start if unset). * **Service name:** `op-succinct-altda`, with a separate `docker-compose-altda.yml` for the AltDA-mode stack. * **Range ELF:** `altda-range-elf-embedded`, embedded at build time. * **Deployment helpers:** `just deploy-oracle .env altda` and `just update-parameters .env altda`. When deploying or upgrading, the range verification key, aggregation verification key, and rollup config hash must be regenerated with `--features altda`. Without this, `OPSuccinctL2OutputOracle` reverts with `ProofInvalid()` on proof submission. ## Limitations The OP Succinct AltDA mode is marked experimental. Configuration keys, feature flags, and on-disk artifacts may change without notice across releases. Pin specific versions for production deployments, and treat the [OP Succinct AltDA documentation](https://succinctlabs.github.io/op-succinct/validity/experimental/altda.html) as the canonical source of truth. Additional limitations to plan around: * **Keccak256 commitments only.** The current implementation accepts only Keccak256 commitments. Generic commitments (the OP alt-DA `0x01` type byte) are explicitly rejected. * **DA availability is operator-enforced.** The zkVM verifies that retrieved data matches the on-chain commitment, but it cannot force the DA server to serve data. Availability and censorship resistance are operator responsibilities. * **No recovery past a missing commitment.** If the DA server loses or refuses to serve data for a given commitment, no proof can be produced for the affected range. There is no recovery path past a missing commitment. * **Hardcoded 30-second HTTP timeout.** The DA fetch timeout is fixed in the current implementation and is not configurable. * **Standard L1 head selection.** The proposer uses standard L1 head selection; there is no Blobstream-style finality tracking. * **Components out of scope for OP Succinct.** The alt-DA server itself, generic-commitment encoding, and on-chain DA challenge/bonding logic are not provided by OP Succinct. ## Deployment Options Three deployment patterns are supported: * **Institution-operated.** The institution runs the full stack: sequencer, `op-node`, `op-batcher`, `op-proposer`, and the AltDA server. * **Conduit-managed.** [Conduit](https://conduit.xyz) operates the full stack as a service, including the AltDA server, on behalf of the institution. * **Gateway-managed.** [Gateway](https://gateway.fm) provides equivalent rollup-as-a-service operation of the stack. ## Settlement And Interop Validity proofs are posted to the chain's `OPSuccinctL2OutputOracle` contract on Ethereum L1, where each proof is verified against a range verification key and rollup config hash pinned at deployment. The chain connects to Agglayer for cross-chain liquidity and state; see the [Agglayer documentation](/interoperability/agglayer) for cross-chain mechanics and integration patterns. ## Resources Architecture, execution clients, rollup modes, and performance. Canonical upstream reference for the AltDA mode used by this configuration. Source code for the OP Succinct prover and AltDA integration. Cross-chain liquidity and state for connected chains. Announcement and positioning of the privacy configuration. Technical write-up from Succinct on the AltDA shipment. # Polygon Developer Docs Source: https://docs.polygon.technology/index The only open, full-stack payments infrastructure for global money movement.
Payments Stablecoins RWAs
Polygon Developer Docs

The open stack for global money movement.

Integrate compliant fiat access, stablecoin settlement, wallet infrastructure, interoperability, and blockchain rails with a single unified stack. Production-ready for institutions moving money at scale.

Open Money Stack

The modular components of the Open Money Stack span fiat & blockchain rails, wallet infrastructure, agentic payments, and interoperability.

Use Cases

The Open Money Stack is infrastructure for financial institutions that need to move money faster, reach more markets, and settle without the overhead of fragmented vendor stacks. These are the problems it solves:

Fund accounts and settle merchants on evenings, weekends, and holidays. Stablecoin rails don't stop when banks do. Build global B2B payment corridors on licensed, compliant infrastructure, without assembling bank relationships from scratch. Let users hold, move, and spend USD without a US bank account. Stablecoin-backed accounts that look like banking. Pay contractors, sellers, and employees across dozens of countries in local fiat or USDC. No per-corridor integrations. Accept stablecoin at checkout, settle in fiat. Near-zero fees, instant finality, and global reach for any merchant. Power US-to-world money transfers with licensed corridors, debit and cash onramps, and stablecoin settlement under the hood.
Resources
} href="https://github.com/0xPolygon" > Explore open-source repos, SDKs, and contracts across the Polygon ecosystem. Check the current operational status of Polygon network services. } href="/tools/index" > SDKs, oracles, indexers, bridges, and security tools for building on Polygon.
# Architecture Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/architecture AggKit's three-tier architecture: chain domain, synchronization components, and the Agglayer ecosystem, with certificate submission and GER propagation flows ## Overview Traditional blockchain architecture assumes you're dealing with a single network. In the Agglayer ecosystem, you're dealing with multiple sovereign chains that each have their own block times, execution environments, and state management. AggKit provides the synchronization layer that keeps all of them coordinated. ## The Three-Tier Architecture AggKit's architecture has three distinct tiers, each with a specific purpose: ### Tier 1: Your Chain's Domain At the foundation, you have **your L2 chain** doing what it does best – processing transactions, executing smart contracts, maintaining state. This is your domain, where you have full sovereignty and control. When users perform bridge operations on your chain, several things happen simultaneously: bridge contracts emit events, state gets updated, and your chain needs to communicate these changes to the broader ecosystem. This is where AggKit steps in. ### Tier 2: The AggKit Synchronization Layer In the middle tier, AggKit components work together to maintain synchronization. Each component has a specialized role: Aggkit *Figure 1: The three-tier architecture – your chain, AggKit synchronization, and the broader ecosystem* ### Tier 3: The Unified Ecosystem At the top tier, you have **the broader Agglayer ecosystem** – Agglayer itself, Ethereum L1, and all the other chains connected to the network. This is where the global state lives, where final settlement happens, and where the unified liquidity that makes everything possible is maintained. ## Data Flow Architecture AggKit handles two directions of communication that keep chain state synchronized with Agglayer: #### **Upward Flow: L2 → Agglayer** **Purpose**: Submits L2 state transitions to Agglayer for validation and proof generation. **Components Involved**: * **BridgeSync**: Captures bridge events from L2 contracts * **L1InfoTreeSync**: Provides L1 verification data and Merkle proofs * **AggSender**: Packages data into signed certificates and submits to Agglayer #### **Downward Flow: Agglayer → L2** **Purpose**: Propagates global state updates from Agglayer/L1 to L2 chains for claim verification. **Components Involved**: * **L1InfoTreeSync**: Monitors L1 for Global Exit Root updates * **AggOracle**: Propagates GER updates to L2 contracts (with v0.3.5 committee security) * **L2GERSync**: Indexes and manages GER state locally on L2 ## Component Interaction Patterns ### **Certificate Generation Pattern** *Figure 2: Certificate generation and submission pattern* ### **Oracle Propagation Pattern** *Figure 3: GER propagation with v0.3.5 committee security* ### **v0.3.5 Security Enhancements** The major architectural improvement in v0.3.5 is the **elimination of single-address vulnerabilities**: #### **Before v0.3.5: Single Point of Failure** **Risk**: Single compromised address could steal funds or mint unauthorized assets. #### **After v0.3.5: Distributed Security** **Security**: Multiple parties must agree before any GER injection, eliminating single points of failure. # AggchainProofGen Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/components/aggchain-proof-gen How AggchainProofGen generates state transition proofs for chains requiring mathematical verification of internal operations beyond ECDSA signature authorization ## What AggchainProofGen Does AggchainProofGen generates state transition proofs for chains that require mathematical verification of internal operations. While chains using a trusted sequencer model can use simple ECDSA signature authorization, some chains need comprehensive proofs that verify both internal operations and cross-chain bridge activities. AggchainProofGen implements the chain-side component of the [State Transition Proof](/interoperability/agglayer/core-concepts/state-transition-proof/) system introduced in Agglayer v0.3. It verifies the chain's consensus mechanism, verifies bridge constraints, and produces an Aggchain Proof that AggSender includes in its certificate. ## When AggchainProofGen Is Needed AggchainProofGen is required for chains that use `CONSENSUS_TYPE = 1` (generic validity proof) rather than `CONSENSUS_TYPE = 0` (ECDSA signature). This applies to: * **Zero-knowledge rollups**: Chains that generate zk-SNARKs or zk-STARKs for state transitions * **Custom consensus chains**: Chains with consensus mechanisms that cannot be authorized by a single trusted sequencer address * **High-security deployments**: Chains where mathematical certainty about state correctness is required rather than trusted-party authorization Chains using ECDSA authorization do not need AggchainProofGen and can operate with AggSender alone. ## How AggchainProofGen Works AggchainProofGen implements a dual verification process: **Step 1: Consensus verification.** AggchainProofGen verifies the chain's consensus: either validating an ECDSA signature from the trusted sequencer, or verifying a validity proof using the SP1 zkVM. **Step 2: Bridge constraint verification.** AggchainProofGen verifies that all bridge operations comply with the Unified Bridge security constraints. This includes GER hash chain validation, claims hash chain validation, Local Exit Root correctness, and GER Merkle proof inclusion in the L1 Info Root. **Step 3: Proof generation.** AggchainProofGen generates an Aggchain Proof combining both verifications. AggSender includes this proof in the certificate it submits to Agglayer. ## Proof Generation Modes ### ECDSA Mode For chains with trusted sequencer models, AggchainProofGen verifies operations using ECDSA signature validation. This provides fast verification while maintaining compatibility with existing chain architectures. ### Validity Proof Mode For chains requiring mathematical certainty, AggchainProofGen generates validity proofs using zero-knowledge virtual machines. This provides cryptographic certainty about the correctness of both internal operations and bridge activities, without relying on a trusted party. ## Integration with AggSender When a chain uses AggchainProofGen, AggSender operates in AggchainProver mode: For the full context of how Aggchain Proof fits into the verification pipeline, see [State Transition Proof](/interoperability/agglayer/core-concepts/state-transition-proof/) and [Aggchain Proof](/interoperability/agglayer/core-concepts/state-transition-proof/aggchain-proof/). # AggOracle Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/components/aggoracle How AggOracle propagates Global Exit Root updates from Ethereum L1 to L2 chains, and the v0.3.5 committee mode security improvement ## What AggOracle Does AggOracle propagates Global Exit Root (GER) updates from Ethereum L1 to the L2 chain's Global Exit Root Manager contract. This synchronization keeps the L2 chain's local copy of global state current, which is required for verifying incoming cross-chain claims. When a user bridges assets from another chain to your chain and submits a claim, your chain verifies the claim against the current GER. Without a current GER, the verification fails and claims cannot be processed. ## The Synchronization Problem Cross-chain claim verification requires L2 chains to have current GER data from Ethereum L1. The two chains operate independently with different block times and finality requirements, so the L2 cannot query L1 directly on demand. AggOracle resolves this by implementing a pull-based synchronization mechanism: it continuously monitors L1 for GER changes and injects updates into the L2 contract whenever a new GER is detected. ## The Two Operating Modes ### Direct Injection Mode (Pre-v0.3.5) In the original design, AggOracle used single-address authorization for GER injection. One designated address had the authority to call `insertGlobalExitRoot()` on the L2 Global Exit Root Manager contract. **Vulnerability**: If the single private key is compromised, an attacker could inject invalid GERs, causing the chain to accept fraudulent bridge claims. ### Committee Mode (v0.3.5) v0.3.5 introduces multi-party consensus. Multiple independent AggOracle instances must agree before any GER injection occurs. **How it works:** 1. Multiple AggOracle committee members independently monitor L1 for GER updates 2. When a new GER is detected, one member proposes it to the committee contract 3. Other members validate and vote by proposing the same GER 4. The committee contract automatically injects the GER when the threshold quorum is reached **Security improvement**: Even if some committee members are compromised, the system remains secure because multiple independent parties must reach consensus before any state update occurs. ## Full GER Propagation Workflow ## Understanding Global Exit Roots A [Global Exit Root (GER)](/interoperability/agglayer/core-concepts/unified-bridge/data-structures/#global-exit-root) is a cryptographic hash that represents the current state of all cross-chain bridge activities across the Agglayer ecosystem: ``` GER = hash(RollupExitRoot, MainnetExitRoot) ``` Where: * **RollupExitRoot**: Aggregated root of all L2 chains' Local Exit Roots * **MainnetExitRoot**: Root of all Ethereum L1 bridge transactions Cross-chain claims require proof verification against the current GER. When users submit bridge claims to your chain, the claim proofs must reference a GER that your chain has recorded as valid. # AggSender Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/components/aggsender How AggSender packages L2 state transitions into cryptographically signed certificates and submits them to Agglayer for Pessimistic Proof generation ## What AggSender Does AggSender is the component responsible for submitting L2 state transitions to Agglayer. It collects bridge events and L1 verification data, packages them into a signed certificate, and submits that certificate to Agglayer on each epoch. Agglayer then uses the certificate to generate a Pessimistic Proof and validate the state transition. Without AggSender, an L2 chain cannot participate in Agglayer's security guarantees or cross-chain coordination. Every chain connected to Agglayer must run AggSender. ## The Trust Problem AggSender Solves Agglayer connects multiple independent blockchains, and any of them could theoretically be compromised. The Pessimistic Proof system limits the damage a compromised chain can do, but it needs reliable input data to work correctly. AggSender provides that input. Rather than simply reporting what happened on a chain, it creates a signed certificate that contains: * Cryptographic proof that bridge transactions occurred * Evidence that the chain has sufficient funds to back those transactions * Mathematical verification data that the chain's state transitions are valid * A digital signature committing to all of the above This allows Agglayer to verify the submission rather than trust it. ## Certificate Generation ### Epoch-Based Operation AggSender submits certificates on Agglayer epochs rather than per-transaction. On each epoch, it collects all bridge activity since the last certificate, packages it, and submits once. This batching is more efficient than per-transaction submissions and provides comprehensive context about the chain's activities. ### Certificate Lifecycle ### Certificate Structure ```go theme={null} type Certificate struct { NetworkID uint32 // L2 network identifier Height uint64 // Certificate sequence number PrevLocalExitRoot common.Hash // Previous Local Exit Root NewLocalExitRoot common.Hash // New Local Exit Root BridgeExits []BridgeExit // Outgoing bridge transactions ImportedBridgeExits []ImportedBridgeExit // Incoming bridge claims Signature []byte // Cryptographic signature Metadata []byte // Additional chain-specific data } ``` ## Full Certificate Submission Flow *Note: AggchainProofGen is only involved when the chain uses the advanced state transition proof system. Chains using basic ECDSA authorization do not require AggchainProofGen.* # BridgeSync Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/components/bridge-sync How BridgeSync monitors and indexes bridge events from L1 and L2 networks, and how it provides data to AggSender and Bridge Service ## What BridgeSync Does BridgeSync monitors bridge contracts on both L1 and L2 networks, captures every bridge-related event, and organizes the data into a local database. It provides the data foundation that other AggKit components depend on: AggSender uses it for certificate construction, and Bridge Service uses it to serve API responses. **Key responsibilities:** * **Event monitoring**: Real-time monitoring of bridge contract events on L1 and L2 * **Data indexing**: Comprehensive indexing of bridge and claim transactions * **State management**: Maintains bridge transaction history and status * **Reorg handling**: Manages blockchain reorganizations and maintains data integrity * **API support**: Provides data to Bridge Service APIs ## Why Indexing Matters Bridge claim verification and status queries require access to bridge transaction history. Without an index, each query would require expensive, slow queries to blockchain nodes or onchain contract calls. BridgeSync captures events as they occur and makes them instantly queryable. AggSender depends on BridgeSync's data to build certificates: it needs the list of bridge exits and imported bridge exits for each epoch. Bridge Service depends on it to respond to transaction status requests and proof generation queries. ## Architecture ## How BridgeSync Works ### Event Processing Workflow ### Bridge Event Types #### BridgeEvent Emitted when assets or messages are bridged from a network: ```solidity theme={null} event BridgeEvent( uint8 leafType, // 0 = asset, 1 = message uint32 originNetwork, // Source network ID address originAddress, // Sender address uint32 destinationNetwork, // Destination network ID address destinationAddress, // Recipient address uint256 amount, // Amount (for assets) bytes metadata, // Additional data uint32 depositCount // Index in Local Exit Tree ); ``` #### ClaimEvent Emitted when assets or messages are claimed on a network: ```solidity theme={null} event ClaimEvent( uint256 globalIndex, // Global transaction index uint32 originNetwork, // Source network ID address originAddress, // Original sender address destinationAddress, // Claim recipient uint256 amount // Claimed amount ); ``` ### Data Processing Pipeline ## Integration with Other Components ### AggSender Integration BridgeSync provides the bridge exit and imported bridge exit data that AggSender packages into certificates: **Data provided:** * Bridge exits (outbound transactions from the L2) * Imported bridge exits (inbound claims to the L2) * Transaction proofs and metadata * Block range information for certificate scope ### Bridge Service Integration BridgeSync is the primary data source for Bridge Service API endpoints: All Bridge Service endpoints query BridgeSync's local database for transaction data. # Components Overview Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/components/index The 7 AggKit components, their roles, dependencies, and which combinations are appropriate for different deployment scenarios ## Modular Design AggKit consists of 7 specialized components. Rather than a single monolithic service, each component handles a specific responsibility. This means you deploy only the components your use case requires. * **Basic Agglayer connectivity**: 2 components (AggSender + AggOracle) * **Full bridge infrastructure**: 5 components (add BridgeSync, L1InfoTreeSync, L2GERSync) * **Bridge API services**: 4 components (BridgeSync, L1InfoTreeSync, L2GERSync, Bridge Service) * **Advanced state transition proofs**: Add AggchainProofGen ## Communication Components These two components are required for any chain connecting to Agglayer. ### AggSender AggSender packages L2 state transitions into cryptographically signed certificates and submits them to Agglayer. On each Agglayer epoch, it collects bridge events from BridgeSync and L1 verification data from L1InfoTreeSync, builds a certificate containing bridge exits and imported bridge exits, signs it, and submits it to Agglayer for Pessimistic Proof generation. Without AggSender, a chain cannot participate in Agglayer's security guarantees or cross-chain coordination. ### AggOracle AggOracle monitors the Global Exit Root contract on Ethereum L1, detects new GER updates, and injects those updates into the L2 chain's Global Exit Root Manager contract. This keeps the chain's local copy of global state current, which is required for verifying incoming cross-chain claims. In v0.3.5, AggOracle operates in committee mode: multiple independent instances must agree on a new GER before it is injected into the L2 contract, eliminating the single-address vulnerability of earlier versions. ## Synchronization Components These components maintain the data that AggSender and AggOracle depend on. ### L1InfoTreeSync L1InfoTreeSync monitors Ethereum L1 and maintains two Merkle trees locally: * **L1 Info Tree**: An append-only tree of historical Global Exit Roots, sourced from `UpdateL1InfoTree` events on the Global Exit Root contract * **Rollup Exit Tree**: A tree of L2 Local Exit Roots, sourced from `VerifyBatches` events on the Rollup Manager contract These trees provide the Merkle proofs that AggSender includes in certificates and that AggOracle uses for GER detection. ### L2GERSync L2GERSync indexes GER injections on the L2 side. When AggOracle writes a new GER to the L2 Global Exit Root Manager contract, L2GERSync captures the event and stores it locally. This local index enables fast GER lookups during claim verification and API responses without requiring onchain queries. ### BridgeSync BridgeSync monitors bridge contracts on both L1 and L2, captures every `BridgeEvent` and `ClaimEvent`, and organizes them into a local database. It provides the bridge exit and imported bridge exit data that AggSender uses for certificate construction, and the transaction history that Bridge Service exposes through its API. ## Service Components These components extend AggKit with external-facing capabilities. ### Bridge Service Bridge Service exposes a REST API over BridgeSync's data. It provides endpoints for bridge transaction status, token mappings, and Merkle proof generation. Applications such as wallets, block explorers, and DeFi protocols use Bridge Service to query bridge data without running the full AggKit infrastructure. ### AggchainProofGen AggchainProofGen generates state transition proofs for chains that require mathematical verification of internal operations rather than simple ECDSA signature authorization. It verifies the chain's consensus (either ECDSA signature or validity proof), verifies bridge constraints, and produces an Aggchain Proof that AggSender includes in its certificate. See [State Transition Proof](/interoperability/agglayer/core-concepts/state-transition-proof/) for the full context of when this is needed. ## Component Dependencies ## Individual component pages Certificate generation, epoch-based operation, and the certificate lifecycle. GER propagation, direct injection vs. committee mode, and the v0.3.5 security change. Bridge event monitoring, data indexing, event types, and integration with AggSender and Bridge Service. The two Merkle trees maintained, event sources, Merkle proof generation, and integration with AggSender and AggOracle. Local GER state management on the L2 side, indexing workflow, and how it supports claim verification. State transition proof generation for chains requiring mathematical verification of internal operations. # L1InfoTreeSync Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/components/l1infotree-sync How L1InfoTreeSync monitors Ethereum L1 and maintains the L1 Info Tree and Rollup Exit Tree for proof generation and certificate building ## What L1InfoTreeSync Does L1InfoTreeSync monitors Ethereum L1 and maintains two local Merkle trees that other AggKit components use for proof generation and certificate building: 1. **L1 Info Tree**: An append-only tree tracking historical Global Exit Root updates from the Global Exit Root contract 2. **Rollup Exit Tree**: An updatable tree tracking rollup state submissions from the Rollup Manager contract Different AggKit operations need different types of L1 data. The L1 Info Tree provides historical GER context for claim verification proofs. The Rollup Exit Tree provides rollup state data for certificate construction. **Key responsibilities:** * Maintaining the L1 Info Tree and Rollup Exit Tree from L1 events * Generating Merkle proofs for cross-chain verification * Handling blockchain reorganizations and maintaining data integrity * Respecting configurable finality requirements (latest, safe, finalized) ## Why L1 State Indexing Matters Cross-chain operations require accurate L1 state for several functions: 1. **Proof generation**: Merkle proofs must reference correct historical L1 states 2. **Certificate building**: AggSender needs L1 data to construct valid certificates 3. **Claim verification**: Cross-chain claims must be verified against settled L1 state 4. **Reorg handling**: L1 reorganizations must be detected and handled Rather than querying L1 on demand for each operation, L1InfoTreeSync maintains a local index that makes proof generation fast and efficient. ## Architecture ## How L1InfoTreeSync Works ### Event Processing L1InfoTreeSync monitors two types of events from Ethereum L1 and processes them into separate tree structures: ### The Two Tree Types **L1 Info Tree (append-only):** * **Source**: `UpdateL1InfoTree` events from the Global Exit Root contract * **Structure**: Append-only tree that grows with each Global Exit Root update * **Purpose**: Provides historical GER data for claim verification * **Use case**: When claim proofs must demonstrate inclusion in a specific historical state **Rollup Exit Tree (updatable):** * **Source**: `VerifyBatches` events from the Rollup Manager contract * **Structure**: Updatable tree where L2 chains can update their submitted state * **Purpose**: Tracks which L2 chains have submitted state and their current exit roots * **Use case**: When AggSender builds certificates that need rollup state context ### Tree Structures #### L1 Info Tree #### Rollup Exit Tree ## Integration with Other Components ### AggSender Integration L1InfoTreeSync provides the L1 data that AggSender includes in certificates: **Data provided:** * Current L1 Info Tree root and leaf data * Merkle proofs for imported bridge exits * L1 block finality information * Historical Global Exit Root data ### AggOracle Integration L1InfoTreeSync feeds GER detection into the AggOracle pipeline: # L2GERSync Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/aggkit/components/l2ger-sync How L2GERSync indexes Global Exit Root updates on the L2 side and provides fast local GER state access for claim verification and Bridge Service APIs ## What L2GERSync Does L2GERSync manages Global Exit Root synchronization on the L2 side. When AggOracle injects a new GER into the L2 Global Exit Root Manager contract, L2GERSync captures the resulting event and stores the GER data in a local index. This local index provides fast access to current and historical GER state for several operations: 1. **Claim verification**: Bridge claims must be verified against the current GER 2. **Proof generation**: Merkle proofs require accurate GER state 3. **API responses**: Bridge Service APIs need fast GER data access 4. **Historical queries**: Applications may need access to historical GER transitions Without L2GERSync, each of these operations would require onchain queries or external service calls, adding latency and external dependencies. ## Architecture ## How L2GERSync Works ### GER Synchronization Workflow L2GERSync automatically detects your contract's capabilities at startup and configures itself for compatibility with the deployed version of the L2 GER Manager contract. # Architecture Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/architecture Agglayer's technical architecture: the Agglayer node, Pessimistic Proof, Unified Bridge, and State Transition Proof and how they coordinate ## Overview Agglayer provides a cross-chain interoperability framework built around four main components: the Agglayer node, the Pessimistic Proof, the Unified Bridge, and the State Transition Proof. Together they enable secure, verifiable cross-chain transactions between heterogeneous blockchain networks. ## High-Level Architecture Agglayer Overall Data Flows *Figure 1: Agglayer Overall Data Flows - showing transaction sequencing, settlement, and L1-L2 synchronization processes* ## Core Components ### 1. Agglayer Node The Agglayer Node is a Rust-based service responsible for processing and verifying zero-knowledge (ZK) proofs from chains connected to the Agglayer. **Key Functions:** * **Zero-knowledge proof verification**: The node receives and verifies cryptographic proofs from connected chains before sending them to L1 * **Certificate management**: Handles certificates that attest to the state transitions of connected chains * **Orchestration of epochs**: Manages state updates in a structured manner through epochs ### 2. Pessimistic Proof The pessimistic proof mechanism ensures that any withdrawal claims made to the Agglayer are backed by legitimate deposits in the Unified Bridge. It uses a novel zero-knowledge proof system implemented in Rust, leveraging the SP1 zkVM and the Plonky3 proving system. **Key Functions:** * **Security validation**: Ensures that each chain connected to the Agglayer remains as secure as if it were operating independently * **State consistency**: Provides a complete view of all token and message transfers occurring across the Agglayer * **Fraud prevention**: Prevents chains from withdrawing more assets than they have legitimately received ### 3. Unified Bridge The unified bridge is responsible for maintaining the data structures related to chain states, cross-chain transactions, and the Agglayer's Global Exit Root, ensuring cross-chain transactions are indeed finalized on the L1 before they can be claimed. **Key Functions:** * **Cross-chain asset transfers**: Allows users to bridge assets between different chains * **Message passing**: Enables contract-to-contract interactions across chains * **State management and accounting**: Maintains Merkle proofs that ensure transactions are finalized before being processed on the destination chain ### 4. State Transition Proof The State Transition Proof is a two-layer verification system that validates both individual chain operations and cross-chain transfers before Agglayer accepts a state update. **How it works:** **State Transition Proof (Validity Proof)**: This layer verifies that each chain's internal state transitions are valid. Every operation within the chain is verified against the chain's execution rules, and the chain's resulting state must be consistent. Additional verification types can be added in the future without changing Agglayer's external interface. **Cross-Chain Verification (Aggchain Proof and Pessimistic Proof)**: This layer verifies that cross-chain operations, such as asset transfers between chains, are valid. It ensures that when assets move between chains, operations are atomic and secure. **Key Functions:** * **End-to-end security**: A transaction is finalized only when both its internal validity proof and its cross-chain proof are accepted * **Atomic cross-chain execution**: Guarantees that assets and messages move between chains in a single, indivisible step * **Modular extensibility**: New proof mechanisms (optimistic, fraud, etc.) can be integrated without altering Agglayer's external interface # Architecture Overview Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/pessimistic-proof/architecture How Pessimistic Proofs are generated and validated, and the financial isolation guarantees they provide ## Overview The Pessimistic Proof is a security mechanism in Agglayer that prevents compromised chains from draining funds beyond their deposits. It enforces a financial firewall between chains so that security issues on one chain cannot spread to the rest of the network. *Figure 1: Complete Pessimistic Proof generation and validation flow* ## How Pessimistic Proofs Work ### Step 0: Local Chain Preparation The local chain prepares data and sends it to Agglayer: * **Initial Network State**: The complete state of the local chain before any state transition occurs, including the Local Exit Tree (recording outbound transactions), Local Balance Tree (tracking token balances), and Nullifier Tree (tracking claimed inbound transactions). This represents the baseline state that will be modified. * **Bridge Exits**: Assets and messages being sent to other chains from the local chain, represented as a vector of BridgeExit structures containing destination information, token details, amounts, and metadata. These represent the outbound state changes that will update the Local Exit Tree and decrease Local Balance Tree balances. * **Imported Bridge Exits**: Assets and messages being claimed to the local chain from other chains, represented as ImportedBridgeExit structures with cryptographic proofs demonstrating their validity. These represent inbound state changes that will update the Nullifier Tree and increase Local Balance Tree balances. ### Step 1: Agglayer Client Data Population Agglayer Client populates the `MultiBatchHeader` using the `Certificate` data: * **Target**: Expected transitioned local chain state (`StateCommitment`) that represents what the new state should look like after applying all the bridge exits and imported bridge exits. This serves as the verification target that the computed state must match. * **Batch Header**: Packaged data with authentication information including previous state roots, all state transition data, balance proofs for affected tokens, cryptographic signatures, and the target state commitment. This comprehensive package contains everything needed for proof generation. ### Step 2: Native Rust Execution Before running expensive zkVM computation, Agglayer runs the Pessimistic Proof Program in native Rust: ```rust theme={null} // Compute new transitioned state let new_state = compute_state_transition(initial_network_state, batch_header); // Compare with expected state if new_state == batch_header.target { return Ok(PessimisticProofOutput); } else { return Err(InvalidStateTransition); } ``` **Process:** 1. Compute new transitioned state using initial state and batch header by applying all bridge exits (reducing balances, updating exit tree) and imported bridge exits (increasing balances, updating nullifier tree) to generate the new Local Balance Tree, Nullifier Tree, and Local Exit Tree roots. 2. Compare computed state with expected state in `batch_header.target` to ensure that the chain's proposed state transition matches the mathematically computed result, validating that the chain is not attempting invalid operations like spending more than available balances. 3. If equal, data is valid and state transition is correct, meaning the chain has provided legitimate state transition data that respects balance constraints and doesn't attempt double-spending or other invalid operations. 4. Return `PessimisticProofOutput` containing the verified state transition data, or error code if validation fails, ensuring that only mathematically valid state transitions can proceed to zkVM proof generation. ### Step 3: zkVM Proof Generation If native execution passes, run the same program in zkVM: * **SP1 Prover Network**: Agglayer uses Succinct's SP1 Prover Network for faster, distributed proof generation. GPU acceleration and optimized precompiles handle the Keccak-heavy computation profile of Pessimistic Proof programs efficiently. * **Same Inputs**: Identical program and inputs as native execution to ensure that the zkVM proof verifies exactly the same computation that was validated in native Rust, maintaining consistency between validation and proof generation phases. * **Proof Generation**: Creates cryptographic proof of correct execution that can be verified by anyone without re-executing the program, providing mathematical certainty that the state transition was computed correctly according to the Pessimistic Proof rules. ### Step 4: Proof Validation Agglayer validates the zk proof returned from the Prover Network: * **Proof Verification**: Verify the cryptographic proof locally using the SP1 verifier to ensure that the proof is mathematically valid and that it corresponds to the expected program execution with the correct inputs and outputs. * **Result Acceptance**: Accept pessimistic proof result if verification passes, confirming that the chain's proposed state transition is mathematically valid and respects all balance and security constraints enforced by the Pessimistic Proof program. * **State Commitment**: Update network state based on verified proof by accepting the new state roots and allowing the chain to proceed with its state transition, enabling subsequent bridge operations to build on the verified state. ## Security Guarantees ### Financial Isolation Each chain effectively has a financial "blast radius" limited to its own deposits: * **Deposit Limit**: Compromised chains cannot drain more than their current deposits because the Pessimistic Proof program mathematically enforces that outbound bridge exits cannot exceed the available token balances in the Local Balance Tree, creating a hard mathematical constraint on fund drainage. * **Containment**: Security issues cannot spread to other chains because each chain's state is validated independently through its own Pessimistic Proof, and the proof verification ensures that compromised chains cannot affect the balance trees or state transitions of other chains in the network. * **Risk Isolation**: Each chain's risk is isolated from the broader ecosystem through the financial "blast radius" concept, where the maximum possible loss from any single chain compromise is limited to the assets currently deposited on that specific chain, protecting the overall network. ### State Transition Verification * **Mathematical Verification**: All state transitions are cryptographically verified through zkVM proof generation that creates mathematical certainty about the correctness of balance updates, nullifier tree modifications, and exit tree changes, preventing any invalid state modifications. * **Proof Requirements**: State changes require valid pessimistic proofs generated through the complete validation pipeline (native execution + zkVM proof generation + verification), ensuring that only mathematically sound state transitions are accepted by the network. * **Consensus Protection**: Invalid proofs are rejected at multiple stages (native execution failure, zkVM proof generation failure, or proof verification failure), maintaining system integrity by preventing any invalid state transitions from being accepted into the network state. ### Network Protection * **Ecosystem Safety**: Broader network remains secure even with individual chain compromises because the Pessimistic Proof system isolates each chain's financial impact and prevents compromised chains from affecting the balance trees, state transitions, or security of other chains in the network. * **Continued Operation**: Other chains continue operating normally during individual chain compromises because each chain's Pessimistic Proof validation is independent, and the failure or compromise of one chain doesn't block or affect the proof generation and validation processes of other chains. * **Trust Boundaries**: Clear trust boundaries between different chains are established through separate Local Balance Trees, independent proof generation, and isolated state validation, ensuring that trust assumptions about one chain don't extend to or affect other chains in the network. ## Performance Characteristics Pessimistic Proof computation is primarily focused on state transition verification: * **75%+ Keccak Operations**: Most computation involves Keccak hash functions used for Merkle tree operations, making Keccak optimization through precompiles and hardware acceleration critical for overall performance of the Pessimistic Proof generation process. * **Merkle Tree Updates**: Efficient updates to Local Balance and Nullifier trees using Sparse Merkle Tree algorithms that only modify affected branches, significantly reducing computation compared to full tree reconstruction while maintaining cryptographic integrity. * **zkVM Optimization**: Performance varies significantly across different zkVM implementations based on their Keccak precompile efficiency, GPU acceleration support, and CPU vectorization capabilities, with SP1 chosen for production due to optimal GPU performance and prover network infrastructure. Execution Graph *Figure 2: Execution profile showing Keccak hash dominance in computation* # Benchmarks Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/pessimistic-proof/benchmarks Experimental performance analysis and benchmarks across different zkVM implementations ## Overview For experimental research and performance analysis of Pessimistic Proof across different zkVM implementations, comprehensive benchmarks have been conducted comparing SP1, RiscZero, Pico, OpenVM, and other zkVMs. **Note**: These benchmarks are for research purposes only. **Production Agglayer uses SP1 and Succinct's Prover Network exclusively.** ## Benchmark Repository For detailed performance analysis, benchmark results, and implementation comparisons across different zkVMs, visit the dedicated benchmark repository: **[Agglayer Pessimistic Proof Benchmarks](https://github.com/BrianSeong99/Agglayer_PessimisticProof_Benchmark/)** ## Repository Contents The benchmark repository includes: * **Performance comparisons**: Cycle counts and execution times across zkVMs * **Implementation details**: How Pessimistic Proof runs on different zkVMs * **Benchmark results**: Data tables and performance graphs * **Setup instructions**: How to run benchmarks locally * **Technical analysis**: Detailed breakdown of computation profiles ## Key Insights Based on the benchmark research: * **Keccak Dominance**: 75%+ of computation involves Keccak hash functions * **Performance Variation**: Significant differences between zkVM implementations * **Hardware Impact**: GPU acceleration and CPU optimizations affect performance * **Production Choice**: SP1 chosen for optimal GPU performance and reliability # Data Structures Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/pessimistic-proof/data-structures Reference for the Sparse Merkle Trees and data structures used by Pessimistic Proof: Local Balance Tree, Nullifier Tree, Bridge Exits, MultiBatchHeader, and Certificate ## Overview Pessimistic Proof computes state transitions between bridging events using three main Sparse Merkle Trees and several supporting data structures. **Core components:** * **Sparse Merkle Trees**: Local Exit Tree, Nullifier Tree, Local Balance Tree * **State transitions**: Bridge Exits, Imported Bridge Exits * **State representations**: Local State, Multi Batch Header, Proof Output ## Unified Bridge Foundation Pessimistic Proof builds on top of the Unified Bridge data structure. For complete understanding, refer to the [Unified Bridge Data Structures](/interoperability/agglayer/core-concepts/unified-bridge/data-structures/). **Key Unified Bridge Components:** * **Local Exit Tree**: Records outgoing cross-chain transactions as cryptographic commitments in a 32-level Sparse Merkle Tree, with each leaf representing a hash of bridge transaction details including destination, amount, and metadata. * **Global Exit Root**: Combines all chain states for verification by computing `hash(RollupExitRoot, MainnetExitRoot)`, providing a single unified root that represents the complete state of cross-chain activities across the entire network. * **Global Index**: Unique 256-bit reference for transactions within Global Exit Root, encoding the source network type (mainnet flag), rollup identifier, and local transaction index to enable precise transaction location across the hierarchical tree structure. Unified Bridge Tree *Figure 1: Unified Bridge data structure foundation* ## Local Balance Tree & TokenInfo The Local Balance Tree tracks all token balances on a chain using a 192-bit depth Sparse Merkle Tree. ### TokenInfo Structure ```rust theme={null} pub struct TokenInfo { /// Network which the token originates from pub origin_network: NetworkId, /// The address of the token on the origin network pub origin_token_address: Address, } ``` ### Key Layout The `TokenInfo` key uses a clever bit layout for efficient storage and lookup: * **First 32 bits**: Origin network ID where the token originally exists, enabling the system to track tokens across multiple chains while maintaining their original identity and preventing confusion between tokens with the same address on different chains. * **Next 160 bits**: Token address on the origin chain (standard Ethereum address size), ensuring that each token can be uniquely identified by combining its origin network and original contract address, even when wrapped versions exist on other chains. ### Balance Updates When assets are bridged out or claimed, the token balance in the Local Balance Tree is updated accordingly through atomic operations that ensure balance conservation and prevent overdraft conditions. Outbound bridging decreases the balance while inbound claiming increases it, with all changes verified through Merkle proof validation. Local Balance Tree *Figure 2: Local Balance Tree structure showing token balance tracking* ## Nullifier Tree The Nullifier Tree prevents double-spending and ensures transaction uniqueness across the network. Each chain maintains its own 64-bit depth Sparse Merkle Tree. ### Key Structure The Nullifier Tree key is constructed using a 64-bit identifier that uniquely identifies each claimable transaction: * **First 32 bits**: Network ID of the chain where the transaction originated, enabling the system to track which source chain a claimed transaction came from and prevent confusion between transactions from different networks. * **Last 32 bits**: Index of the bridge exit within the Local Exit Tree of the source chain (also called Local Index or depositCount), providing the exact position of the transaction within the source chain's bridge transaction history. ### Double-Spending Prevention Nullifier Tree *Figure 3: Nullifier Tree structure preventing double-spending* ## Bridge Exits Bridge Exits represent outbound transactions from a chain. ### Structure ```rust theme={null} pub struct BridgeExit { /// Enum, 0 is asset, 1 is message pub leaf_type: LeafType, /// Unique ID for the token being transferred pub token_info: TokenInfo, /// Network which the token is transferred to pub dest_network: NetworkId, /// Address which will own the received token pub dest_address: Address, /// Token amount sent pub amount: U256, /// PermitData, CallData, etc. pub metadata: Vec, } ``` ### Usage All outbound transactions from a chain are represented in a `BridgeExit` vector during pessimistic proof generation. Each `BridgeExit` contains complete transaction information needed to validate that the chain has sufficient balance for the outbound transfer and to update the Local Exit Tree with the new transaction commitment. ## Imported Bridge Exits Imported Bridge Exits represent inbound transactions to a chain. ### Structure ```rust theme={null} pub struct ImportedBridgeExit { /// The bridge exit from the source network pub bridge_exit: BridgeExit, /// The claim data pub claim_data: Claim, /// The global index of the imported bridge exit pub global_index: GlobalIndex, } ``` ### Claim Data Types ```rust theme={null} pub enum Claim { Mainnet(Box), Rollup(Box), } ``` **Separation Reason**: L1 and Rollup claims require different proof paths due to their different positions in the hierarchical tree structure: * **Mainnet**: Requires direct proof from Mainnet Exit Root to L1 Info Root since L1 transactions are recorded directly in the Mainnet Exit Tree and don't need to go through the Rollup Exit Tree aggregation layer. * **Rollup**: Requires a two-step proof path from Local Exit Root → Rollup Exit Root → L1 Info Root because L2 transactions must first prove inclusion in the L2's Local Exit Tree, then prove that the L2's Local Exit Root was properly submitted to the Rollup Exit Tree on L1. ## Local State Local State represents the complete state of a local chain. ### Structure ```rust theme={null} pub struct LocalNetworkState { /// Commitment to the BridgeExit pub exit_tree: LocalExitTree, /// Commitment to the balance for each token pub balance_tree: LocalBalanceTree, /// Commitment to claimed assets on foreign networks pub nullifier_tree: NullifierTree, } ``` ### Components * **Exit Tree**: Records all outgoing bridge transactions as a 32-level Sparse Merkle Tree, storing cryptographic commitments of `bridgeAsset` and `bridgeMessage` operations that represent assets and messages being sent to other chains. * **Balance Tree**: Tracks token balances for all assets on the chain using a 192-bit depth Sparse Merkle Tree, with TokenInfo keys enabling precise tracking of token origins and current balances for every asset type on the chain. * **Nullifier Tree**: Prevents double-spending of claimed assets by maintaining a 64-bit depth Sparse Merkle Tree that marks imported bridge exits as claimed, ensuring that each cross-chain transaction can only be processed once on the destination chain. ## Multi Batch Header The comprehensive state transition record for pessimistic proof generation. ### Structure ```rust theme={null} pub struct MultiBatchHeader { /// Network that emitted this MultiBatchHeader pub origin_network: NetworkId, /// Previous local exit root pub prev_local_exit_root: H::Digest, /// Previous local balance root pub prev_balance_root: H::Digest, /// Previous nullifier tree root pub prev_nullifier_root: H::Digest, /// List of bridge exits created in this batch pub bridge_exits: Vec, /// List of imported bridge exits claimed in this batch pub imported_bridge_exits: Vec<(ImportedBridgeExit, NullifierPath)>, /// Commitment to the imported bridge exits pub imported_exits_root: Option, /// L1 info root used to import bridge exits pub l1_info_root: H::Digest, /// Token balances with Merkle proofs pub balances_proofs: BTreeMap)>, /// Signer committing to the state transition pub signer: Address, /// Signature committing to the state transition pub signature: Signature, /// State commitment target hashes pub target: StateCommitment, } ``` ### Purpose Serves as the master input capturing the complete set of changes between old and new local states, containing all data required for pessimistic proof generation. This structure packages together the previous state roots, all state transition data (bridge exits and imported bridge exits), balance proofs, and target state commitments needed to mathematically verify that the proposed state transition is valid and secure. ## Pessimistic Proof Output The final result of Pessimistic Proof computation. ### Structure ```rust theme={null} pub struct PessimisticProofOutput { /// The previous local exit root pub prev_local_exit_root: Digest, /// The previous pessimistic root pub prev_pessimistic_root: Digest, /// The l1 info root for proving imported bridge exits pub l1_info_root: Digest, /// The origin network of the pessimistic proof pub origin_network: NetworkId, /// The consensus hash pub consensus_hash: Digest, /// The new local exit root pub new_local_exit_root: Digest, /// The new pessimistic root (balance + nullifier tree) pub new_pessimistic_root: Digest, } ``` ### Pessimistic Root Formula ``` prev_pessimistic_root = hash(prev_local_balance_root, prev_nullifier_root) new_pessimistic_root = hash(new_local_balance_root, new_nullifier_root) ``` ## Certificate A Certificate represents a state transition of a chain that gets submitted to Agglayer. ### Structure ```rust theme={null} pub struct Certificate { /// NetworkID of the origin network pub network_id: NetworkId, /// Simple increment to count the Certificate per network pub height: Height, /// Previous local exit root pub prev_local_exit_root: Digest, /// New local exit root pub new_local_exit_root: Digest, /// List of bridge exits included in this state transition pub bridge_exits: Vec, /// List of imported bridge exits included in this state transition pub imported_bridge_exits: Vec, /// Signature committed to the bridge exits and imported bridge exits pub signature: Signature, /// Fixed size field of arbitrary data for the chain needs pub metadata: Metadata, } ``` ### Validation If a certificate is invalid, any state transitions in the current epoch will be reverted, protecting the network from invalid state changes. The validation process ensures that all bridge exits have sufficient balances, all imported bridge exits have valid proofs and haven't been double-claimed, and that the cryptographic signature properly commits to all the state transition data. This atomic validation prevents partial state updates that could compromise network security. # Proof Generation Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/pessimistic-proof/proof-generation The Pessimistic Proof generation pipeline: certificate submission, native Rust validation, zkVM proof generation, and proof verification ## Overview Pessimistic Proof generation is a multi-step process that verifies state transitions mathematically before Agglayer accepts them. The process runs the proof program first in native Rust for fast validation, then in a zkVM to produce a cryptographic proof. ## Proof Generation Flow ### Complete Flow ### Step 1: Certificate Submission Local chains submit a **`Certificate`** containing comprehensive state transition data: * **Previous and new local exit roots** that define the starting and ending states of the chain's **Local Exit Tree**, providing the boundary conditions for validating the proposed state transition. * **Bridge exits** (outbound transactions) representing all assets and messages being sent from this chain to other chains, with complete destination information, token details, and amounts that will reduce the chain's **Local Balance Tree**. * **Imported bridge exits** (inbound transactions) representing all assets and messages being claimed on this chain from other chains, with **cryptographic proofs** demonstrating their validity and **Global Index** information for verification. * **Cryptographic signature** from the chain's authorized signer that commits to all the state transition data, ensuring that the certificate represents an authorized state transition approved by the chain's governance or operator. ### Step 2: Data Population Agglayer Client creates a **`MultiBatchHeader`** from the Certificate: * Adds **previous state roots** (balance, nullifier, exit) from the initial network state to establish the baseline from which state transitions will be computed and validated. * Includes **balance proofs** for affected tokens by providing **Merkle proofs** demonstrating the current balances in the **Local Balance Tree** for all tokens involved in bridge exits, ensuring that sufficient funds exist for outbound transfers. * Sets **target state commitment** representing the expected final state after applying all bridge exits and imported bridge exits, serving as the verification target that the computed state transition must match. * Adds **authentication data** including **cryptographic signatures**, signer addresses, and **L1 Info Root** references needed to validate the legitimacy and timing of the state transition request. ### Step 3: Native Execution Before expensive zkVM computation, Agglayer runs the Pessimistic Proof program in native Rust to validate the state transition: **The Process:** 1. **Apply State Transitions**: The program takes the **initial network state** and applies all the changes specified in the **batch header**. For **bridge exits**, it reduces token balances and adds new leaves to the **Local Exit Tree**. For **imported bridge exits**, it checks **nullifier uniqueness**, increases token balances, and marks transactions as claimed in the **Nullifier Tree**. 2. **Compute New State**: After applying all transitions, the program computes the new roots for all three **Merkle trees** (**Exit Tree**, **Balance Tree**, **Nullifier Tree**) and creates a new **state commitment** that represents the final state after all changes. 3. **Validate Against Target**: The computed new state is compared against the **target state** provided in the certificate. If they match, it proves that the chain's proposed state transition is **mathematically correct** and respects all balance and security constraints. 4. **Generate Output**: If validation succeeds, the program generates a **`PessimisticProofOutput`** containing both the previous and new state roots, which serves as the verified result of the state transition computation. ```rust theme={null} pub fn generate_pessimistic_proof( initial_state: &LocalNetworkState, batch_header: &MultiBatchHeader, ) -> Result { // Compute new state based on transitions let new_state = apply_state_transitions(initial_state, batch_header)?; // Verify against expected target if new_state.commitment() != batch_header.target { return Err(ProofError::InvalidStateTransition); } // Return proof output Ok(PessimisticProofOutput { prev_local_exit_root: batch_header.prev_local_exit_root, prev_pessimistic_root: compute_pessimistic_root( batch_header.prev_balance_root, batch_header.prev_nullifier_root ), new_local_exit_root: new_state.exit_tree.root(), new_pessimistic_root: compute_pessimistic_root( new_state.balance_tree.root(), new_state.nullifier_tree.root() ), // ... other fields }) } ``` ### Step 4: zkVM Execution If native execution succeeds, run the identical program in zkVM: * **Same Program**: Exact same proof generation function executed in the zkVM environment to ensure that the cryptographic proof verifies the identical computation that was validated in native Rust, maintaining consistency between validation and proof phases. * **Same Inputs**: Identical initial state and batch header data fed to the zkVM to guarantee that the proof generation uses exactly the same parameters that were validated in native execution, preventing any discrepancies between validation and proving. * **Cryptographic Proof**: Generates verifiable proof of correct execution that can be validated by anyone without re-executing the program, providing mathematical certainty that the state transition computation was performed correctly according to Pessimistic Proof rules. ### Step 5: Proof Validation Agglayer validates the returned zk proof: * **Proof Verification**: Cryptographic verification of the proof using the SP1 verifier to ensure mathematical validity and confirm that the proof corresponds to the expected program execution with correct inputs and outputs. * **Output Validation**: Ensure proof output matches expected results by comparing the PessimisticProofOutput from the zkVM execution with the results from native execution, validating consistency between both execution environments. * **State Acceptance**: Update network state if proof is valid by accepting the new state roots and allowing the chain to proceed with its state transition, enabling subsequent operations to build on the verified state. ## State Transition Logic The state transition mechanism validates and applies changes from the old local state to the new local state using bridge exits and imported bridge exits, then compares the computed results with the expected certificate data. ## Proof Verification ### Mathematical Constraints The proof generation enforces several mathematical constraints: 1. **Balance Conservation**: Total outbound amounts ≤ available balances, mathematically enforced by verifying that the sum of all bridge exit amounts for each token does not exceed the current balance stored in the Local Balance Tree, preventing overdraft conditions. 2. **Nullifier Uniqueness**: No double-claiming of imported exits, enforced by checking that each imported bridge exit's nullifier key is not already marked as claimed in the Nullifier Tree, preventing replay attacks and duplicate processing. 3. **Root Consistency**: All tree roots must be computed correctly using the standard Keccak256 hashing algorithm and Sparse Merkle Tree algorithms, ensuring that state transitions produce mathematically valid tree structures. 4. **Signature Validity**: State transitions must be properly signed by the chain's authorized signer using valid cryptographic signatures that commit to all the state transition data, ensuring that only authorized parties can propose state changes. ### Security Guarantees * **No Overdraft**: Chains cannot spend more than they have because the Pessimistic Proof program mathematically enforces balance conservation by verifying that outbound bridge exit amounts do not exceed available token balances in the Local Balance Tree, creating a hard constraint against fund drainage. * **No Double-Spending**: Each transaction can only be claimed once due to the Nullifier Tree mechanism that marks imported bridge exits as claimed and prevents re-processing, ensuring that the same cross-chain transaction cannot be used multiple times to inflate balances. * **Cryptographic Integrity**: All state changes are cryptographically verified through Merkle tree operations using Keccak256 hashing, zkVM proof generation, and signature validation, ensuring that no invalid state modifications can be accepted by the system. * **Atomic Updates**: All changes succeed or fail together through the comprehensive validation process where any failure in balance verification, nullifier checking, or signature validation causes the entire state transition to be rejected, preventing partial updates that could compromise system integrity. # Aggchain Proof Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/state-transition-proof/aggchain-proof Reference for Aggchain Proof: ECDSA and generic validity proof consensus types, data structures, verification steps, and bridge constraint details ## Overview Aggchain Proof is the verification layer in Agglayer that handles different consensus mechanisms for proving chain state transitions. It combines consensus verification with bridge constraint verification, producing a single proof that covers both a chain's internal operations and its cross-chain transfers. ## Supported Consensus Types ### ECDSA Signature (CONSENSUS\_TYPE = 0) The original consensus mechanism used in Agglayer where a **trusted sequencer** acts as a security authority, signing off on state changes to ensure they are valid and authorized. **Characteristics:** * **Trusted Sequencer Model**: A designated address signs off on state changes, acting as the primary security authority for the chain * **Simple Verification**: Like having a security guard verify and approve changes - fast and straightforward * **Fast Processing**: Minimal computational overhead with efficient signature verification * **Trust Assumption**: Relies on sequencer integrity and key security **How ECDSA Verification Works:** 1. **Message Construction**: Create standardized message combining **SHA256** of public values, **new local exit root**, and **commitment to imported bridge exits** 2. **Signature Recovery**: Use elliptic curve cryptography to recover the signer's address from the signature 3. **Authority Validation**: Compare recovered address with configured **trusted sequencer** address ```rust theme={null} // ECDSA Verification Implementation pub fn verify(&self) -> Result<(), ProofError> { let signature_commitment = keccak256_combine([ self.sha256_public_values(), new_local_exit_root.0, commit_imported_bridge_exits.0, ]); let recovered_signer = signature .recover_address_from_prehash(&B256::new(signature_commitment.0))?; if recovered_signer != self.trusted_sequencer { return Err(ProofError::InvalidSigner); } Ok(()) } ``` ### Generic Proof / Validity Proof (CONSENSUS\_TYPE = 1) Advanced consensus mechanism providing comprehensive verification of chain operations through mathematical proofs rather than trusted parties. **Characteristics:** * **Flexible Proof System**: Can work with any type of chain-specific proof system * **Mathematical Verification**: Provides comprehensive state transition validation with cryptographic certainty * **Universal Compatibility**: Like having a universal translator for different security protocols * **Enhanced Security**: Mathematical certainty about state correctness without trust assumptions **How Validity Proof Works:** 1. **State Transition Verification**: Mathematically verify every operation within the chain, including transaction processing, smart contract execution, and state machine transitions 2. **Bridge Constraint Verification**: Verify that cross-chain transfers are valid and properly integrated with internal state changes 3. **SP1 zkVM Verification**: Use **SP1 zkVM** to cryptographically verify the validity proof with mathematical certainty ```rust theme={null} // Validity Proof Verification Implementation pub fn verify(&self) -> Result<(), ProofError> { // Verify L1 head for synchronization self.verify_l1_head(l1_info_root)?; // Verify the validity proof using SP1 zkVM sp1_zkvm::lib::verify::verify_sp1_proof( &self.aggregation_vkey_hash.to_hash_u32(), &self.sha256_public_values().into(), ); Ok(()) } ``` **Use Cases:** * **Zero-Knowledge Rollups**: Chains generating **zk-SNARKs** or **zk-STARKs** for state transitions * **Custom Consensus**: Chains with unique consensus algorithms and specialized verification requirements ## Aggchain Proof Data Structure ### Witness Structure ```rust theme={null} pub struct AggchainProofWitness { /// Previous local exit root pub prev_local_exit_root: Digest, /// New local exit root pub new_local_exit_root: Digest, /// L1 info root used to import bridge exits pub l1_info_root: Digest, /// Origin network for which the proof was generated pub origin_network: u32, /// Full execution proof with its metadata pub fep: FepInputs, /// Commitment on the imported bridge exits minus the unset ones pub commit_imported_bridge_exits: Digest, /// Bridge witness related data pub bridge_witness: BridgeWitness, } ``` ### Bridge Witness ```rust theme={null} pub struct BridgeWitness { /// List of inserted GER minus the removed ones pub inserted_gers: Vec, /// Raw list of inserted GERs which includes also the ones which get removed pub raw_inserted_gers: Vec, /// List of removed GER pub removed_gers: Vec, /// List of each imported bridge exit containing global index and leaf hash pub bridge_exits_claimed: Vec, /// List of global index of each unset bridge exit pub global_indices_unset: Vec, /// State sketch for the prev L2 block pub prev_l2_block_sketch: EvmSketchInput, /// State sketch for the new L2 block pub new_l2_block_sketch: EvmSketchInput, } ``` ### Public Values Output ```rust theme={null} pub struct AggchainProofPublicValues { /// Previous local exit root pub prev_local_exit_root: Digest, /// New local exit root pub new_local_exit_root: Digest, /// L1 info root used to import bridge exits pub l1_info_root: Digest, /// Origin network for which the proof was generated pub origin_network: NetworkId, /// Commitment to the imported bridge exits indexes pub commit_imported_bridge_exits: Digest, /// Chain-specific commitment forwarded by the PP pub aggchain_params: Digest, } ``` ## Verification Process ### Step 1: Consensus Verification The system first verifies the chain's consensus proof: ```rust theme={null} // Verify the FEP proof or ECDSA signature self.fep.verify( self.l1_info_root, self.new_local_exit_root, self.commit_imported_bridge_exits, )?; ``` **For ECDSA**: Verifies signature from trusted sequencer **For Generic**: Verifies validity proof using chain-specific verification logic ### Step 2: Bridge Constraints Verification Then verifies bridge-related constraints: ```rust theme={null} // Verify the bridge constraints self.bridge_constraints_input().verify()?; ``` **Bridge Verification Components:** 1. **GER Hash Chains**: Verifies **Global Exit Root** insert/remove sequences recorded in hash chains that act as a stack using LIFO rules 2. **Claims Hash Chains**: Verifies claimed and unset claims hash chains where valid claims are added to claimed chain and invalid ones to unset chain 3. **Local Exit Root**: Verifies the **Local Exit Root** is computed correctly 4. **Imported Bridge Exits**: Verifies **`commit_imported_bridge_exits`** is constructed correctly from claimed and unset bridge events 5. **GER Inclusion**: Verifies each inserted **Global Exit Root** has valid **Merkle proof** inclusion in the **L1 Info Root** ## Execution Flow ### Complete Aggchain Proof Process ## Bridge Constraint Details ### GER Stack Management **Global Exit Root** updates are managed as a sophisticated stack structure that ensures proper sequencing and validation: * **Insertion Process**: New **Global Exit Roots** are added when bridge operations occur on any connected chain. Each insertion represents a state change in the **Unified Bridge** system and must be properly validated and sequenced to maintain network consistency. * **Removal Mechanism**: Faulty **Global Exit Roots** can be removed from the stack in rare cases where invalid state updates are detected. This removal process ensures that incorrect state updates don't propagate through the network and compromise security. * **LIFO Order**: Last-in-first-out ordering ensures proper sequence validation where the most recent **GER** updates are processed first. This ordering is critical for maintaining temporal consistency and ensuring that state updates are applied in the correct chronological order. * **Hash Chain Tracking**: All **GER** operations (both insertions and removals) are recorded in cryptographically linked hash chains that provide an immutable audit trail. These hash chains enable verification that the **GER** stack operations were performed correctly and in the proper sequence. ### Claims Processing **Bridge Exit Claims** are processed with comprehensive dual tracking that ensures security and prevents double-spending: * **Claimed Hash Chain**: Valid claims that successfully increase balances on destination chains are recorded in a cryptographically linked hash chain. Each entry in this chain represents a legitimate cross-chain transfer that has been properly verified and processed, creating an immutable record of successful bridge operations. * **Unset Hash Chain**: Invalid claims that are rejected due to insufficient proofs, double-spending attempts, or other validation failures are recorded in a separate hash chain. This tracking ensures that invalid operations are properly documented and cannot be reprocessed, maintaining system integrity. * **Atomic Processing**: All claims in a batch succeed or fail together through comprehensive validation where any single claim failure causes the entire batch to be rejected. This atomic processing prevents partial state updates that could compromise balance consistency across chains. * **Double-Spend Prevention**: Ensures each bridge exit can only be claimed once by tracking all processed claims in the **Nullifier Tree** and validating that imported bridge exits haven't been previously processed. This mechanism prevents replay attacks and maintains economic security. ### Inclusion Proof Verification **L1 Info Root Inclusion** provides cryptographic proof that **Global Exit Root** updates are legitimate: * **Merkle Proof Validation**: Each inserted **Global Exit Root** must have a valid **Merkle proof** demonstrating inclusion in the **L1 Info Tree**. These proofs use **Keccak256** hashing to create cryptographic certainty that the **GER** was properly recorded on L1. * **L1 Settlement Verification**: Proofs demonstrate that **Global Exit Root** updates were properly recorded on L1 and achieved finality, ensuring that cross-chain operations are backed by Ethereum's security guarantees and cannot be reverted. * **Leaf Index Validation**: Ensures correct positioning in the **L1 Info Tree** by validating that the **Merkle proof** corresponds to the expected leaf index. This prevents manipulation of proof paths and ensures that proofs reference the correct historical state. * **Root Verification**: Confirms that **Merkle proofs** lead to the correct **L1 Info Root** by reconstructing the proof path and validating that it produces the expected root hash. This verification ensures that proofs are based on legitimate L1 state and haven't been tampered with. # Architecture Overview Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/state-transition-proof/architecture The State Transition Proof dual proof system: Local Chain, AggProver, and Agglayer roles, and how ECDSA and generic consensus types are handled ## Overview State Transition Proof implements a dual proof system that verifies both internal chain operations and cross-chain transfers. It supports chains with different consensus mechanisms while maintaining consistent security guarantees at the Agglayer level. ## Dual Proof Architecture ### Complete Verification Flow ## System Components ### Local Chain **Purpose**: Chains connected to Agglayer (Katana, X Layer, and others) that generate state transition proofs. **Key Responsibilities:** * **State Transition Confirmation**: Validates that internal state changes are mathematically correct and follow the chain's consensus rules * **Proof Generation**: Creates either **Validity Proofs** (comprehensive state verification) or **ECDSA Signatures** (trusted sequencer authorization) depending on the chain's security model * **Certificate Submission**: Packages state transition data into certificates for Agglayer verification ### AggProver **Purpose**: Critical component that generates cryptographic proofs for state transitions and bridge operations. **Key Responsibilities:** * **Consensus Verification**: Validates either **Validity Proofs** or **ECDSA Signatures** from local chains to ensure state transitions are authorized and mathematically correct * **Bridge Constraint Validation**: Verifies **Global Exit Root** sequences, claimed/unset bridge events, **Local Exit Root** correctness, and **L1 Info Root** inclusion proofs * **Aggchain Proof Generation**: Creates comprehensive proofs that combine consensus verification with bridge validation, ensuring both internal and cross-chain operations are secure ## Verification Systems ### Internal Chain Validation **State Transition Verification:** * Validates that each chain's internal state transitions are mathematically correct through comprehensive verification of all operations within the chain * Ensures all operations follow proper execution rules and that new states are properly derived from previous states through valid state transition logic * Provides the foundation for secure cross-chain operations by ensuring individual chains are operating correctly before allowing bridge operations **Consensus Mechanisms:** * **Validity Proof**: Comprehensive verification of every operation in the chain using mathematical proofs, providing cryptographic certainty about state correctness without requiring trusted parties * **ECDSA Signature**: Trusted sequencer authorization where designated addresses validate and sign off on state changes, providing fast verification with trusted party assumptions ### Cross-Chain Validation **Aggchain Proof:** * Combines consensus verification with bridge constraint validation to ensure both internal operations and cross-chain transfers are secure and mathematically correct * Supports flexible consensus mechanisms while maintaining strict bridge security requirements, enabling different chain types to participate safely * Acts as the bridge between internal chain validation and cross-chain operation validation **Pessimistic Proof:** * Validates cross-chain asset transfers and balance conservation by ensuring chains cannot drain more funds than currently deposited, creating financial isolation between chains * Prevents compromised chains from affecting other chains in the network through mathematical constraints on fund movement * Ensures atomic cross-chain operations where all components succeed or fail together ## Consensus Flexibility ### ECDSA Consensus (CONSENSUS\_TYPE = 0) **Characteristics:** * **Trusted Sequencer**: Designated address signs state transitions * **Simple Verification**: Signature validation using elliptic curve cryptography * **Fast Processing**: Minimal computational overhead * **Trust Model**: Relies on sequencer integrity ### Generic Consensus (CONSENSUS\_TYPE = 1) **Characteristics:** * **Validity Proofs**: Comprehensive mathematical verification of state transitions * **Flexible Integration**: Supports various proof systems and zkVMs * **Enhanced Security**: Mathematical certainty about state correctness * **Modular Design**: Can integrate with different chain architectures ## Security Guarantees ### Comprehensive Validation * **Internal Security**: Every chain's internal operations are verified through either **Validity Proofs** or **ECDSA signatures** before any cross-chain operations are allowed, ensuring that only properly functioning chains can participate in bridge operations * **Cross-Chain Security**: Bridge operations are validated through multiple proof systems (**Aggchain Proof** + **Pessimistic Proof**) that ensure mathematical correctness and balance conservation across all connected chains * **Mathematical Certainty**: All verifications use cryptographic proofs and mathematical constraints to provide certainty about operation validity, eliminating reliance on trust assumptions where possible ### Isolation and Containment * **Chain Independence**: Issues in one chain cannot affect others due to isolated verification processes where each chain's state transitions are validated independently through separate proof generation and verification * **Atomic Operations**: All operations succeed or fail completely through the comprehensive validation pipeline where any failure in consensus verification, bridge constraints, or pessimistic proof validation causes the entire state transition to be rejected * **Proof Requirements**: Invalid operations cannot proceed without proper verification because the system requires valid cryptographic proofs at multiple stages (consensus + bridge + balance conservation) before accepting any state changes # Architecture Overview Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/unified-bridge/architecture The Unified Bridge architecture: onchain contracts, off-chain services, data flow, and security properties ## Overview The Unified Bridge combines onchain smart contracts, off-chain services, and cryptographic verification to enable cross-chain communication across Agglayer-connected chains. Unified Bridge Architecture *Figure 1: Complete Unified Bridge architecture showing all components and interactions* ## System Architecture ## Data Flow Architecture ### Cross-Chain Transaction Flow ## Component Interactions ### Smart Contract Layer **L1 Contracts (Ethereum):** * **RollupManager**: Coordinates L2 state submissions and manages the Rollup Exit Tree. When L2s submit their Local Exit Roots, this contract updates the aggregated rollup state and triggers Global Exit Root updates. * **GlobalExitRoot**: Maintains the unified Global Exit Root by combining Rollup Exit Root and Mainnet Exit Root. Also manages the L1 Info Tree that stores historical Global Exit Roots for L2 synchronization. * **Bridge**: Handles L1 ↔ L2 transactions and maintains the Mainnet Exit Tree. Processes asset and message bridging from L1 to connected L2s, and validates claims from L2s to L1. **L2 Contracts (Connected Chains):** * **Bridge**: Handles all cross-chain transactions for the L2, including bridging to other L2s and L1. Maintains the chain's Local Exit Tree and processes both outbound bridging and inbound claims. * **GlobalExitRootL2**: Syncs with L1 Global Exit Root updates to enable claim verification. Fetches the latest Global Exit Root from L1 to validate cross-chain transaction proofs. ### Service Layer **Bridge Services:** * **Chain Indexer**: Monitors blockchain events in real-time, parsing and organizing bridge transaction data. Each connected chain has its own indexer instance that processes `BridgeEvent` and `ClaimEvent` logs. * **Transaction API**: Provides real-time bridge transaction status and details for user interfaces. Returns transaction status, token information, source/destination chains, and deposit counts needed for proof generation. * **Proof API**: Generates Merkle proofs required for claiming bridged assets and messages. Creates `smtProofLocalExitRoot` and `smtProofRollupExitRoot` along with other verification data needed for claims. ### Security Architecture ## Bridge Operation Types ### Asset Bridging Architecture **Source Chain Process:** 1. Lock/burn tokens based on token type 2. Record transaction in Local Exit Tree 3. Emit bridge event for indexing **Destination Chain Process:** 1. Verify Merkle proofs against Global Exit Root 2. Transfer/mint tokens based on token type 3. Mark transaction as claimed ### Message Bridging Architecture **Source Chain Process:** 1. Package message data and ETH value 2. Record message in Local Exit Tree 3. Emit bridge event for indexing **Destination Chain Process:** 1. Verify Merkle proofs against Global Exit Root 2. Execute message on target contract 3. Handle ETH/WETH value transfer ## State Synchronization ### Global Exit Root Updates ### Merkle Tree Hierarchy The architecture maintains a sophisticated hierarchical Merkle tree structure that enables secure cross-chain verification: * **Local Exit Trees**: Each connected chain maintains its own 32-level Sparse Merkle Tree that records all outgoing bridge transactions. Every time a user initiates a `bridgeAsset` or `bridgeMessage` call, a new leaf is added to this tree and the root is updated. * **Rollup Exit Tree**: L1's RollupManager maintains a Sparse Merkle Tree where each leaf represents a Local Exit Root from a connected L2. When L2s submit their updated Local Exit Roots to L1, this tree is updated, creating a unified view of all L2 bridge activities. * **Mainnet Exit Tree**: L1 maintains its own Local Exit Tree (called Mainnet Exit Tree) that records all bridge transactions originating from L1 to connected L2s. This operates similarly to L2 Local Exit Trees but specifically for L1 activities. * **Global Exit Root**: A single root hash computed as `hash(RollupExitRoot, MainnetExitRoot)` that represents the complete state of all cross-chain activities across the entire network. This root is updated whenever either the Rollup Exit Root or Mainnet Exit Root changes. * **L1 Info Tree**: A historical ledger that stores every Global Exit Root update as leaves in a 32-level Sparse Merkle Tree. This enables L2s to sync with specific historical states and provides the foundation for Merkle proof verification during claims. ## Scalability Design ### Horizontal Scaling * **Multiple L2s**: The architecture supports unlimited connected chains without performance degradation. Each new L2 simply adds another leaf to the Rollup Exit Tree, and the system scales linearly with the number of connected chains. * **Parallel Processing**: Connected chains operate independently and can process bridge transactions simultaneously. There's no coordination required between chains for individual transactions, enabling true parallel execution across the network. * **Load Distribution**: Proof generation and transaction indexing are distributed across multiple service instances. Each chain can have its own indexer, and proof generation can be handled by distributed prover networks. ### Vertical Scaling * **Batch Submissions**: L2s have flexibility in how frequently they submit their Local Exit Roots to L1. They can submit immediately for each transaction or batch multiple transactions together before submitting, optimizing for gas costs and throughput. * **Efficient Proofs**: Merkle proof generation is optimized using Sparse Merkle Trees that only store non-zero values, significantly reducing storage and computation requirements. Proofs are generated on-demand and cached for frequently accessed transactions. * **State Compression**: The hierarchical tree structure provides natural compression where multiple L2 states are represented by a single Rollup Exit Root, and the entire network state is compressed into a single Global Exit Root. ## Security Properties ### Trust Model * **L1 Security**: The system inherits Ethereum's security guarantees because all cross-chain transactions must be settled and finalized on Ethereum before they can be claimed on destination chains. This means the security of cross-chain operations is backed by Ethereum's consensus mechanism and economic security. * **Cryptographic Proofs**: Every claim requires valid Merkle proofs that mathematically demonstrate the transaction was properly recorded and settled. The verification process uses cryptographic hash functions to ensure that no invalid or fraudulent claims can be processed. * **No Trusted Parties**: The system operates without requiring trust in any centralized entity. Users, claimers, and even the bridge operators cannot manipulate the system because all operations are governed by smart contract logic and cryptographic verification. ### Failure Isolation * **Chain Independence**: If one connected chain experiences issues or becomes compromised, it cannot affect the security or operation of other chains. Each chain's bridge transactions are isolated in separate Local Exit Trees, preventing cross-contamination of security issues. * **Atomic Operations**: Bridge transactions either succeed completely or fail completely - there are no partial states. If any part of a cross-chain transaction fails (such as insufficient balance or invalid proofs), the entire operation is reverted without affecting the system state. * **Proof Requirements**: Invalid operations cannot be executed because the system requires valid Merkle proofs for all claims. Without proper cryptographic proof that a transaction was settled on L1, no assets can be claimed or messages executed on destination chains. # Asset Bridging Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/unified-bridge/asset-bridging How asset bridging works in the Unified Bridge: token type handling, bridgeAsset/claimAsset function signatures, and Merkle proof verification ## Overview Asset bridging enables the transfer of tokens and native assets between Agglayer-connected chains. The Unified Bridge handles different token types with distinct mechanisms depending on whether the token originates from the source chain or is a foreign token. Asset Bridging Process *Figure 1: Complete asset bridging flow from L1 to L2* ## Supported Token Types The Unified Bridge handles different token types with specific mechanisms: | Token Type | Source Chain Action | Destination Chain Action | | -------------------------------------------- | --------------------------------- | ------------------------------------- | | **Native Gas Token** (ETH, Custom Gas Token) | Bridge contract holds tokens | Bridge contract transfers tokens | | **WETH** | Burn WETH tokens from user | Mint WETH tokens to user | | **Foreign ERC20** (Not native to source) | Burn ERC20 tokens from user | Mint wrapped tokens to user | | **Native ERC20** (Native to source) | Transfer ERC20 to bridge contract | Transfer from bridge contract to user | ## Bridge Asset Function The `bridgeAsset` function initiates asset transfers between chains. ### Function Signature ```solidity theme={null} function bridgeAsset( uint32 destinationNetwork, address destinationAddress, uint256 amount, address token, bool forceUpdateGlobalExitRoot, bytes calldata permitData ) external payable ``` ### Parameters * **`destinationNetwork`**: Network ID of the destination chain * **`destinationAddress`**: Address to receive assets on destination chain * **`amount`**: Amount of tokens to bridge * **`token`**: Token contract address (0x0 for native gas token) * **`forceUpdateGlobalExitRoot`**: Whether to update GER immediately * **`permitData`**: Raw permit data for ERC20 tokens (optional) ### Process Steps 1. **Validation**: Check destination network is not the source network 2. **Token Preparation**: Handle token based on type (lock, burn, or transfer) 3. **Event Emission**: Emit `BridgeEvent` with transaction details 4. **Tree Update**: Add transaction to Local Exit Tree as leaf node ### Token Preparation Logic The bridge handles different token types with specific mechanisms based on their origin and nature: > Note that in case `ETH` is the native token, WETHToken will be at `0x0` address. #### Native Gas Token (ETH, Custom Gas Token) ```solidity theme={null} // Bridge contract holds the tokens // The native gas token is already transferred via msg.value // No additional token transfer required ``` #### WETH Token ```solidity theme={null} // Burn WETH tokens from user's address IWETH(token).burnFrom(msg.sender, amount); ``` #### Foreign ERC20 Token (Not native to source chain) ```solidity theme={null} // If the token contract is not originally from the source network, // burn the ERC20 token from user's address IERC20(token).burnFrom(msg.sender, amount); ``` #### Native ERC20 Token (Native to source chain) ```solidity theme={null} // If the token contract is originally from the source network: // 1. Execute permit if provided if (permitData.length > 0) { IERC20Permit(token).permit(...); } // 2. Transfer tokens from user to bridge contract IERC20(token).transferFrom(msg.sender, address(this), amount); ``` ## Claim Asset Function The `claimAsset` function claims bridged assets on the destination chain. ### Function Signature ```solidity theme={null} function claimAsset( bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata ) external ``` ### Parameters * **`smtProofLocalExitRoot`**: Merkle proof for Local Exit Root * **`smtProofRollupExitRoot`**: Merkle proof for Rollup Exit Root * **`globalIndex`**: Global index identifying the transaction * **`mainnetExitRoot`**: Mainnet Exit Root at time of transaction * **`rollupExitRoot`**: Rollup Exit Root at time of transaction * **`originNetwork`**: Network ID of source chain * **`originTokenAddress`**: Token address on source chain * **`destinationNetwork`**: Network ID of destination chain * **`destinationAddress`**: Address to receive assets * **`amount`**: Amount of tokens to claim * **`metadata`**: Additional metadata (if any) ### Process Steps 1. **Validation**: Verify destination network matches current chain 2. **Proof Verification**: Verify Merkle proofs against Global Exit Root 3. **Duplicate Check**: Ensure transaction hasn't been claimed before 4. **Token Transfer**: Transfer tokens based on token type (see Token Transfer Logic below) 5. **Claim Record**: Mark transaction as claimed ### Token Transfer Logic Once the proof verification passes, the bridge claims tokens using different mechanisms based on the token type: | Token type | Action | | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | **ETH is gas token** | Bridge contract transfers the amount from itself to the destination address | | **WETH where ETH is not gas token** | Mint new WETH tokens to the destination address | | **Custom gas token** | Bridge contract transfers the amount from itself to the destination address | | **Native ERC20 Token** | If the token contract is originally from this destination network, transfer the ERC20 token from bridge contract to destination address | | **Foreign ERC20 Token, First time bridging** | Deploy a new ERC20 Token contract to host this new Foreign ERC20 Token, and mint the transfer amount to destination address | | **Foreign ERC20 Token, Contract exists** | Mint the transfer amount to destination address | ### Proof Verification Logic ```solidity theme={null} // Construct Global Exit Root bytes32 globalExitRoot = keccak256(abi.encodePacked(mainnetExitRoot, rollupExitRoot)); // Verify against synchronized GER require(globalExitRoot == getGlobalExitRoot(), "Invalid global exit root"); // Verify Merkle proofs based on origin if (originNetwork == 0) { // L1 to L2: Verify against mainnet exit root verifyMerkleProof(smtProofLocalExitRoot, mainnetExitRoot, globalIndex); } else { // L2 to L2: Verify against rollup exit root verifyMerkleProof(smtProofLocalExitRoot, rollupExitRoot, globalIndex); verifyMerkleProof(smtProofRollupExitRoot, rollupExitRoot, globalIndex); } ``` ## Bridging Flows ### L1 to L2 Bridging ### L2 to L1 Bridging ### L2 to L2 Bridging # Bridge Components Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/unified-bridge/bridge-components Reference for the Unified Bridge's onchain contracts, off-chain services, and APIs ## Overview The Unified Bridge consists of three main component categories: onchain smart contracts, off-chain services, and developer tools. Unified Bridge Components *Figure 1: Complete Unified Bridge architecture showing all components and their interactions* ## Smart Contracts The core onchain infrastructure deployed on each connected chain. ### PolygonZKEVMBridgeV2.sol **Purpose**: Main bridge contract that serves as the interface for all cross-chain transactions. **Key Functions**: * `bridgeAsset()`: Initiates asset transfers between chains by validating destination networks, handling different token types (native gas tokens, WETH, ERC20), locking or burning tokens on the source chain, and recording the transaction in the Local Exit Tree. * `bridgeMessage()`: Initiates message transfers between chains by packaging message data with optional ETH value, validating gas token conditions, and recording the message in the Local Exit Tree for later execution on the destination chain. * `claimAsset()`: Claims bridged assets on the destination chain by verifying Merkle proofs against the Global Exit Root, ensuring the transaction hasn't been claimed before, and transferring or minting the appropriate tokens to the recipient address. * `claimMessage()`: Claims bridged messages on the destination chain by verifying Merkle proofs, executing the message on the target contract (if it implements `IBridgeMessageReceiver`), and handling ETH/WETH value transfers. **Data Management**: * Maintains Local Exit Tree (LET) for the chain as a 32-level Sparse Merkle Tree, storing cryptographic commitments of all outgoing bridge transactions and updating the root with each new transaction. * Records all outgoing bridge transactions with complete transaction details including destination network, recipient address, token amounts, and metadata, creating an immutable audit trail. * Handles complex token operations including locking native tokens in escrow, burning foreign tokens, transferring native ERC20 tokens, and minting wrapped tokens on destination chains based on token origin and type. **Deployment**: Deployed on both L1 and all connected L2s ### PolygonRollupManager.sol **Purpose**: L1 contract that manages rollup state updates and coordinates L2 submissions. **Key Functions**: * `updateRollupExitRoot()`: Updates the rollup exit root when L2s submit their Local Exit Roots, validating the cryptographic proofs and ensuring the submitted state transitions are legitimate before updating the aggregated rollup state. * `verifyBatches()`: Verifies L2 batch submissions by checking zero-knowledge proofs that demonstrate the validity of state transitions, ensuring that all transactions in the batch were executed correctly according to the L2's rules. * `sequenceBatches()`: Sequences L2 batches on L1 by ordering and timestamping batch submissions, providing a canonical ordering of L2 operations that enables deterministic state reconstruction. **Data Management**: * Maintains Rollup Exit Tree (RET) as a Sparse Merkle Tree where each leaf represents a Local Exit Root from a connected L2, enabling efficient aggregation of all L2 bridge states into a single root hash. * Tracks all L2 Local Exit Roots by storing the latest submitted root from each connected chain along with metadata like submission timestamps and batch numbers for audit and synchronization purposes. * Updates Global Exit Root when RET changes by automatically triggering updates in the `PolygonZkEVMGlobalExitRootV2.sol` contract, ensuring the unified global state reflects all L2 bridge activities. **Deployment**: Deployed only on L1 ### PolygonZkEVMGlobalExitRootV2.sol **Purpose**: L1 contract that maintains the Global Exit Root (GER) and L1 Info Tree. **Key Functions**: * `updateGlobalExitRoot()`: Updates the Global Exit Root when either the Rollup Exit Root or Mainnet Exit Root changes, computing the new GER as `hash(RollupExitRoot, MainnetExitRoot)` and appending it to the L1 Info Tree for historical tracking and L2 synchronization. * `getGlobalExitRoot()`: Returns the current Global Exit Root that represents the unified state of all cross-chain activities across the entire network, used by L2s for synchronization and by users for generating claim proofs. * `getL1InfoTreeRoot()`: Returns the root of the L1 Info Tree which contains all historical Global Exit Roots, enabling L2s to sync with specific historical states and generate valid Merkle proofs for transactions from any point in time. **Data Management**: * Maintains Global Exit Root (hash of RER and MER) as the single source of truth for the entire network's cross-chain state, automatically recalculating whenever either component root changes to ensure consistency. * Maintains L1 Info Tree with historical GERs as a 32-level Sparse Merkle Tree, storing every Global Exit Root update as a timestamped leaf to enable historical state queries and proof generation for past transactions. * Provides GER synchronization for L2s by exposing the latest Global Exit Root and L1 Info Tree root, allowing L2 contracts to fetch and verify the current unified state for processing incoming cross-chain claims. **Deployment**: Deployed only on L1 ### PolygonZkEVMGlobalExitRootL2.sol **Purpose**: L2 contract that synchronizes with L1 Global Exit Root updates. **Key Functions**: * `updateExitRoot()`: Syncs with the latest Global Exit Root from L1 by calling the L1 Global Exit Root contract, fetching the current GER and L1 Info Tree root, and updating the L2's local copy to enable validation of incoming cross-chain claims. * `getGlobalExitRoot()`: Returns the current synchronized Global Exit Root stored on this L2, which is used by the bridge contract to verify Merkle proofs during claim operations and ensure claims are based on the latest global state. * `getL1InfoTreeRoot()`: Returns the synchronized L1 Info Tree root that corresponds to the current Global Exit Root, enabling the L2 to validate that claim proofs are based on legitimate historical states from the L1 Info Tree. **Data Management**: * Maintains synchronized copy of L1 GER by periodically fetching updates from the L1 Global Exit Root contract and storing them locally, ensuring the L2 has the latest unified network state for claim verification. * Maintains synchronized copy of L1 Info Tree root along with the corresponding Global Exit Root, creating a consistent state snapshot that enables proper validation of Merkle proofs during cross-chain claim operations. * Enables L2 to verify cross-chain claims by providing the necessary Global Exit Root and L1 Info Tree root data that the bridge contract uses to validate Merkle proofs and ensure claimed transactions were properly settled on L1. **Deployment**: Deployed on all connected L2s ## Bridge Service Off-chain infrastructure that provides indexing, APIs, and proof generation services. ### Chain Indexer Framework **Purpose**: EVM blockchain data indexer that parses and organizes blockchain data. **Key Features**: * **Real-time Indexing**: Continuously monitors the blockchain for bridge-related events by subscribing to new blocks and scanning for `BridgeEvent` and `ClaimEvent` logs, ensuring that all cross-chain transactions are captured immediately as they occur. * **Data Parsing**: Extracts and structures bridge transaction data from raw blockchain logs, converting hex-encoded event data into structured formats that include transaction details, token information, addresses, amounts, and timestamps. * **Event Processing**: Processes `BridgeEvent` logs (emitted during bridging) and `ClaimEvent` logs (emitted during claiming) to track the complete lifecycle of cross-chain transactions from initiation to completion. * **Database Storage**: Stores indexed data in structured databases optimized for API queries, enabling fast retrieval of transaction history, status updates, and proof generation data for user interfaces and applications. **Deployment**: One instance per connected chain **Technology**: Built on Polygon's Chain Indexer Framework ### Transaction API **Purpose**: Provides real-time bridge transaction status and details for user interfaces. **Key Endpoints**: * **Testnet**: `https://api-gateway.polygon.technology/api/v3/transactions/testnet?userAddress={userAddress}` * **Mainnet**: `https://api-gateway.polygon.technology/api/v3/transactions/mainnet?userAddress={userAddress}` **Response Data**: * Transaction status (pending, completed, failed) with real-time updates as transactions progress through the bridging and claiming phases * Token details including contract addresses, transfer amounts, token symbols, and decimals for accurate display in user interfaces * Source and destination chain information including network IDs, chain names, and block numbers where transactions were processed * Timestamps for transaction initiation, L1 settlement, and claim completion to track transaction lifecycle timing * Deposit count (Local Exit Tree index) required for Merkle proof generation during the claim process **Authentication**: Requires API key in request header **Example Usage**: ```bash theme={null} curl --location 'https://api-gateway.polygon.technology/api/v3/transactions/mainnet?userAddress=0x...' \ --header 'x-api-key: ' ``` ### Proof Generation API **Purpose**: Generates Merkle proofs required for claiming bridged assets and messages. **Key Endpoints**: * **Testnet**: `https://api-gateway.polygon.technology/api/v3/proof/testnet/merkle-proof?networkId={sourceNetworkId}&depositCount={depositCount}` * **Mainnet**: `https://api-gateway.polygon.technology/api/v3/proof/mainnet/merkle-proof?networkId={sourceNetworkId}&depositCount={depositCount}` **Parameters**: * `networkId`: Network ID registered on Agglayer that identifies the source chain (0 for Ethereum/Sepolia, 1 for Polygon zkEVM/Cardona, etc.), used to determine which Local Exit Tree contains the transaction. * `depositCount`: The leaf index from the source chain's Local Exit Tree (obtained from Transaction API response), which specifies exactly which transaction leaf to generate proofs for. **Response Data**: * `smtProofLocalExitRoot`: Merkle proof demonstrating that the specific transaction exists in the source chain's Local Exit Tree, providing the cryptographic path from the transaction leaf to the Local Exit Root. * `smtProofRollupExitRoot`: Merkle proof demonstrating that the source chain's Local Exit Root exists in the Rollup Exit Tree on L1 (only needed for L2 to L1/L2 transactions), proving the L2's state was properly submitted to L1. * `globalIndex`: The 256-bit Global Index that uniquely identifies this transaction within the entire network, encoding the source network type, rollup ID, and local index information. * `mainnetExitRoot`: The Mainnet Exit Root at the time this transaction was processed, used for constructing the Global Exit Root during claim verification. * `rollupExitRoot`: The Rollup Exit Root at the time this transaction was processed, used for constructing the Global Exit Root during claim verification. **Authentication**: Requires API key in request header ### Auto Claim Service (only on L2s) **Purpose**: Automated service that claims bridged transactions on destination chains. **Key Features**: * **Automatic Claiming**: Continuously monitors for claimable transactions across all connected chains by querying the Transaction API, detecting when transactions are ready to be claimed (L1 finalized), and automatically executing claim transactions to complete the cross-chain transfer. * **Gas Optimization**: Optimizes gas usage for claim transactions by batching multiple claims together when possible, using dynamic gas pricing based on network conditions, and implementing efficient claim strategies to minimize transaction costs. * **Error Handling**: Handles failed claims gracefully by implementing retry mechanisms with exponential backoff, logging detailed error information for debugging, and providing fallback strategies when primary claim methods fail. * **Monitoring**: Provides comprehensive monitoring and alerting for claim operations including success/failure rates, processing times, gas usage statistics, and automated notifications when manual intervention is required. **Deployment Options**: * **DApp Integration**: Deploy as part of your dApp infrastructure to provide automatic claiming for your users, eliminating manual claim steps in cross-chain workflows. * **Chain Integration**: Deploy as a chain-level service where the L2 operator runs the claiming service for all users, providing a public good that improves the overall user experience on that chain. * **Standalone Service**: Deploy as an independent claiming service that can serve multiple dApps or chains, potentially monetized through small fees or operated as a community service. **Configuration**: * Source and destination chain RPC URLs for monitoring bridge events and submitting claim transactions across all supported networks * Bridge contract addresses for each supported chain to interact with the correct bridge instances * Private keys for claiming with appropriate security measures and key rotation policies * Gas price settings including maximum gas prices, priority fees, and dynamic pricing strategies based on network congestion # Data Structures Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/unified-bridge/data-structures Reference for the Unified Bridge Merkle tree hierarchy: Local Exit Root, Rollup Exit Root, Mainnet Exit Root, Global Exit Root, and Global Index ## Overview The Unified Bridge uses a hierarchical Merkle tree structure to track and verify all cross-chain transactions. Every transaction is cryptographically verifiable, and source chain transactions must be finalized on L1 before they can be claimed on the destination chain. Unified Bridge Data Structure *Figure 1: Complete data structure hierarchy showing how Local Exit Roots, Rollup Exit Root, Mainnet Exit Root, and Global Exit Root work together* ## Local Exit Root & Local Index Each Agglayer connected chain maintains its own Local Exit Tree (LET) that records all outgoing cross-chain transactions. ### Local Exit Tree (LET) * **Structure**: A 32-level binary Sparse Merkle Tree that efficiently stores bridge transaction data. The tree uses a sparse representation, meaning it only stores non-zero values, making it highly efficient for storing mostly-empty trees with occasional transactions. * **Purpose**: Records all bridge transactions initiated on the chain as cryptographic commitments. Each outgoing `bridgeAsset` or `bridgeMessage` transaction is hashed and stored as a leaf node, creating an immutable record of all cross-chain activities originating from this chain. * **Storage**: Maintained in the `PolygonZKEVMBridgeV2.sol` contract deployed on each chain. This contract serves as both the user interface for bridge operations and the storage mechanism for the Local Exit Tree state. * **Updates**: The tree root is recalculated and updated with each new cross-chain transaction. This ensures that the Local Exit Root always represents the current state of all bridge transactions from this chain. ### Local Index (depositCount) * **Definition**: The sequential index of the leaf node in the Local Exit Tree, starting from 0 and incrementing by 1 for each new transaction. This creates a unique identifier for each bridge transaction within the chain's Local Exit Tree. * **Value**: Each leaf at this index represents a Keccak256 hash of a complete cross-chain transaction, including all transaction details like destination chain, recipient address, token amount, and metadata. * **Increment**: Automatically incremented with each new bridge transaction, ensuring that every cross-chain operation gets a unique position in the tree. This index is crucial for generating Merkle proofs during the claim process. Local Exit Tree *Figure 2: Local Exit Tree structure showing how bridge transactions are recorded as leaves* ## Rollup Exit Root The Rollup Exit Root (RER) is the Merkle root of all L2s' Local Exit Roots, maintained on L1. ### How it Works 1. **L2 Submission**: Connected L2s periodically submit their updated Local Exit Root to the `PolygonRollupManager.sol` contract on L1. This submission includes cryptographic proof that the Local Exit Root represents valid bridge transactions that have been properly sequenced and finalized on the L2. 2. **Frequency**: L2s have flexibility in submission timing - they can submit their Local Exit Root immediately after each bridge transaction for fastest finality, or batch multiple transactions together before submitting to optimize for L1 gas costs and throughput. 3. **RER Update**: The RollupManager validates the submitted Local Exit Root and updates the corresponding leaf in the Rollup Exit Tree. This creates a new Rollup Exit Root that represents the aggregated state of all connected L2s' bridge activities. 4. **GER Update**: When the Rollup Exit Root changes, it automatically triggers an update to the Global Exit Root in the `PolygonZkEVMGlobalExitRootV2.sol` contract, ensuring the unified state is always current. ### Key Contracts * **PolygonRollupManager.sol**: Manages L2 state updates on L1 by validating submitted Local Exit Roots, maintaining the Rollup Exit Tree, and coordinating with the Global Exit Root contract for unified state updates. * **PolygonZkEVMGlobalExitRootV2.sol**: Automatically updates the Global Exit Root whenever the Rollup Exit Root or Mainnet Exit Root changes, and manages the L1 Info Tree for historical GER tracking. Rollup Exit Tree *Figure 3: Rollup Exit Tree showing how L2 Local Exit Roots are aggregated* ## Mainnet Exit Root The Mainnet Exit Root (MER) tracks L1 to L2 bridge transactions, similar to how L2s track their outgoing transactions. ### How it Works 1. **L1 Bridge**: When users initiate bridge transactions from L1 to connected L2s, these transactions are recorded directly in L1's own Local Exit Tree (called Mainnet Exit Tree). This happens immediately within the same transaction that initiates the bridge operation. 2. **MER Update**: The Mainnet Exit Root is automatically updated in the `PolygonZkEVMGlobalExitRootV2.sol` contract whenever L1 bridge transactions occur. Unlike L2s, L1 doesn't need to submit its Local Exit Root separately since the Global Exit Root contract is on L1 itself. 3. **GER Update**: Any Mainnet Exit Root update immediately triggers a Global Exit Root recalculation, which then gets appended to the L1 Info Tree for L2 synchronization. ### Key Difference * **L2s**: Must submit their Local Exit Roots to L1 via the RollupManager contract, creating a two-step process where L2 transactions are first finalized locally, then submitted to L1 for global state updates. * **L1**: Updates its own Mainnet Exit Root directly within the Global Exit Root contract during the bridge transaction itself, eliminating the need for separate submission transactions. Mainnet Exit Tree *Figure 4: Mainnet Exit Tree showing how L1 bridge transactions are tracked* ## Global Exit Root The Global Exit Root (GER) is the root hash that combines both Rollup Exit Root and Mainnet Exit Root. ### Formula ``` GER = hash(RollupExitRoot, MainnetExitRoot) ``` ### L1 Info Tree The L1 Info Tree is a 32-level binary Sparse Merkle Tree that maintains all Global Exit Roots: * **Purpose**: Serves as a historical record of all Global Exit Root updates, enabling L2s to synchronize with specific points in time and generate valid Merkle proofs for claims. This tree is essential for the claim verification process. * **Height**: Uses 32 levels to provide sufficient capacity for storing Global Exit Root updates over the system's lifetime. The sparse nature means only populated leaves consume storage. * **Updates**: A new leaf is added to the tree each time the Global Exit Root changes (either from Rollup Exit Root or Mainnet Exit Root updates). Each leaf contains the new Global Exit Root value along with timestamp information. * **Sync**: L2s periodically call the `updateExitRoot` function on their `PolygonZkEVMGlobalExitRootL2.sol` contract to fetch and synchronize with the latest Global Exit Root from L1, ensuring they can validate incoming claims. ### Global Index The Global Index is a 256-bit identifier that uniquely locates each cross-chain transaction within the global system: | Bits | Purpose | Description | | -------- | ---------------- | ------------------------------------------------------------------------------------------------------ | | 191 bits | Unused | Reserved bits typically filled with zeros for cost efficiency in storage and computation | | 1 bit | Mainnet Flag | Indicates transaction origin: 0 = transaction from L2 rollup, 1 = transaction from L1 mainnet | | 32 bits | Rollup Index | Identifies the specific L2 rollup within the Rollup Exit Tree (only used when mainnet flag = 0) | | 32 bits | Local Root Index | The depositCount/leaf index within the source chain's Local Exit Tree where this transaction is stored | This structure enables efficient lookup of any transaction across the entire network by encoding the path through the hierarchical tree structure. L1 Info Tree *Figure 5: L1 Info Tree structure showing how Global Exit Roots are maintained* ## Data Flow ### Flow for L1 -> L2 Bridge Asset 1. User/Developer/Dapp initiate `bridgeAsset` call on L1 2. Bridge contract on L1 appends an exit leaf to mainnet exit tree of the L1, and update its mainnet exit root. 3. Global exit root manager appends the new L1 mainnet exit root to global exit tree and computes the new global exit root. 4. L2 sequencer fetches and updates the latest global exit root from the global exit root manager. 5. User/Developer/Dapp/Chain initiates `claimAsset` call, and also provides the smtProof. 6. Bridge contract on destination L2 chain validates the smtProof against the global exit root on its chain. If passes next step. 7. Transfer/Mint the asset to the destination address. Bridge Asset L1 to L2 ### Flow for L2 -> L1 Bridge Message 1. User/Developer/Dapp initiate `bridgeMessage` call on L2 2. Bridge contract on L2 appends an exit leaf to local exit tree of the L2, and update its local exit root on L2. 3. Sends the new local exit root to L1 to verify, once passed the L2's local exit root, aka the leaf node in the rollup exit tree will be updated, which will cause a chain of updates to Global exit root updates on L1 and also L1InfoTree updates. 4. User/Developer/Dapp/Chain initiates `claimMessage` call, and also provides the smtProof. 5. Bridge contract on destination L1 chain validates the smtProof against the global exit root on its chain. If passes next step. 6. Execute `onMessageReceived` process. Bridge Message L2 to L1 # Message Bridging Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/unified-bridge/message-bridging How message bridging works in the Unified Bridge: bridgeMessage/claimMessage function signatures, the IBridgeMessageReceiver interface, and execution flows ## Overview Message bridging enables smart contracts on different chains to communicate and trigger execution across chains. A contract on the source chain calls `bridgeMessage` with encoded function data, and the bridge executes that data on the destination contract when the message is claimed. Message Bridging Process *Figure 1: Complete message bridging flow from L2 to L1* ## Message Model ### What Message Bridging Supports * **Contract-to-contract communication**: Smart contracts can trigger function calls on other chains * **Cross-chain state updates**: Contracts can update state on destination chains * **Trustless communication**: Cryptographic verification of all cross-chain messages via Merkle proofs ### Message Structure Cross-chain messages contain: * **Destination contract**: Address of the contract to execute on the destination chain * **Function data**: Encoded function call data * **Value**: ETH value to send with the message (if any) * **Gas limit**: Maximum gas for execution on the destination chain * **Metadata**: Additional data for the message ## Bridge Message Function The `bridgeMessage` function initiates message transfers between chains. ### Function Signature ```solidity theme={null} function bridgeMessage( uint32 destinationNetwork, address destinationAddress, uint256 gasLimit, bytes calldata data ) external payable ``` ### Parameters * **`destinationNetwork`**: Network ID of the destination chain * **`destinationAddress`**: Address of the contract to execute on destination chain * **`gasLimit`**: Maximum gas for execution on destination chain * **`data`**: Encoded function call data ### Process Steps 1. **Validation**: Check destination network is not the source network 2. **Value Handling**: Handle ETH value if provided 3. **Event Emission**: Emit `BridgeEvent` with message details 4. **Tree Update**: Add message to Local Exit Tree as leaf node ### Example Usage ```solidity theme={null} // Bridge a message to call a function on destination chain bridgeMessage( 1, // destinationNetwork (L2) 0x..., // destinationAddress (contract address) 100000, // gasLimit abi.encodeWithSignature("updateValue(uint256)", 123) // data ); ``` ## Claim Message Function The `claimMessage` function claims and executes bridged messages on the destination chain. ### Function Signature ```solidity theme={null} function claimMessage( bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 gasLimit, bytes calldata data ) external ``` ### Parameters * **`smtProofLocalExitRoot`**: Merkle proof for Local Exit Root * **`smtProofRollupExitRoot`**: Merkle proof for Rollup Exit Root * **`globalIndex`**: Global index identifying the message * **`mainnetExitRoot`**: Mainnet Exit Root at time of message * **`rollupExitRoot`**: Rollup Exit Root at time of message * **`originNetwork`**: Network ID of source chain * **`originAddress`**: Address that sent the message * **`destinationNetwork`**: Network ID of destination chain * **`destinationAddress`**: Address of the contract to execute * **`gasLimit`**: Maximum gas for execution * **`data`**: Encoded function call data ### Process Steps 1. **Validation**: Verify destination network matches current chain 2. **Proof Verification**: Verify Merkle proofs against Global Exit Root 3. **Duplicate Check**: Ensure message hasn't been claimed before 4. **Message Execution**: Execute the message on destination contract 5. **Claim Record**: Mark message as claimed ### Message Execution ```solidity theme={null} // Execute the message on destination contract (bool success, bytes memory returnData) = destinationAddress.call{ value: msg.value, gas: gasLimit }(data); require(success, "Message execution failed"); ``` **Important Notes:** * Messages can only be executed if the `destinationAddress` is a smart contract that implements the `IBridgeMessageReceiver` interface * If the receiving address is an EOA, the call will result as a success, meaning that the amount of ether will be transferred correctly, but the message will not trigger any execution * If the native gas token is `ETH`, then transfer `ETH` to the `destinationAddress` and execute the message * If `ETH` is not the native gas token, then mint `WETH` to the `destinationAddress` and execute the message ### IBridgeMessageReceiver Interface For a contract to receive bridged messages, it must implement the `IBridgeMessageReceiver` interface: ```solidity theme={null} interface IBridgeMessageReceiver { function onMessageReceived( address originAddress, uint32 originNetwork, bytes calldata data ) external payable; } ``` **Parameters:** * `originAddress`: Address that sent the message on the source chain * `originNetwork`: Network ID of the source chain * `data`: The message data/metadata sent from source chain ## Bridging Flows ### L1 to L2 Message Bridging ### L2 to L1 Message Bridging ### L2 to L2 Message Bridging # What is Agglayer? Source: https://docs.polygon.technology/interoperability/agglayer/core-concepts/what-is-agglayer CDK's interoperability layer: how it addresses blockchain fragmentation and what it enables for CDK chains Agglayer is the interoperability layer built into every Polygon Chain Development Kit (CDK) chain. When you deploy a CDK chain, it connects to Agglayer by default — the cross-chain capabilities described here come as part of the infrastructure, not as a separate integration step. ## The Blockchain Fragmentation Problem Today's blockchain ecosystem is fragmented by design. Ethereum provides well-established security and a deep DeFi ecosystem. Polygon offers fast transactions and low fees. Arbitrum uses optimistic rollup technology. Each chain has evolved to solve specific problems, but they exist in isolation. The result is that users must manage multiple wallets, developers rebuild the same functionality across chains, and assets remain trapped in their respective ecosystems. Moving ETH from Ethereum into a DeFi protocol on Polygon requires bridging, waiting for confirmations, dealing with wrapped tokens, and accepting the risk of multi-step cross-chain operations. ## What Agglayer Is Agglayer is CDK's built-in interoperability layer. Rather than building bridges between specific pairs of chains, it creates shared infrastructure where: * **Assets maintain their identity across chains.** No wrapped tokens. ETH on Ethereum is the same ETH you use on a connected chain. * **Operations are atomic across multiple chains.** A cross-chain transaction either succeeds on all involved chains or fails entirely, with no partial states. * **Security is enforced mathematically.** Cryptographic proofs replace trusted validators. The system assumes any chain could be compromised and builds constraints around that assumption. * **Chains remain sovereign.** Connected chains keep their own architecture, consensus rules, and governance. Agglayer provides interoperability without requiring chains to give up independence. ## How Agglayer Works ### The Three Security Gateways **Gateway 1: The Unified Bridge** The Unified Bridge is where cross-chain transactions execute. When assets or messages move between chains, the Unified Bridge handles cryptographic verification and state management using Merkle tree structures that track every cross-chain operation. Transactions are settled on Ethereum before they can be claimed on destination chains. **Gateway 2: Pessimistic Proof** Rather than assuming all chains are honest, Agglayer assumes they might be compromised. The Pessimistic Proof system mathematically enforces that even if a chain's prover is unsound, it cannot withdraw more funds than are currently deposited on that chain. A compromised chain's damage is limited to its own deposits and cannot spread to the rest of the network. **Gateway 3: State Transition Proof** Introduced in Agglayer v0.3, the State Transition Proof adds a second verification layer that validates individual chain operations before cross-chain proofs are applied. This ensures both that a chain is operating correctly internally and that cross-chain operations are secure. ### Why Distrust Is the Foundation Traditional bridges require trust: a multi-signature wallet, a validator set, or a smart contract with administrative keys. There is always a point of centralized risk. Agglayer inverts this model. It starts from the assumption that any connected chain could be compromised and then enforces mathematical constraints that bound the damage: * Compromised provers cannot drain more than their chain's deposits. * Cryptographic proofs verify every operation rather than relying on authoritative validation. * Problems on one chain cannot spread to others because each chain's state is verified independently. ## Why This Matters for CDK Chains ### For chain operators Your CDK chain participates in a shared network by default. Assets on your chain can move to and from other connected chains without bridging infrastructure you need to build or maintain. Cross-chain liquidity and connectivity come with the deployment. ### For developers building on CDK chains Applications can use the best properties of each chain in the network. High-value operations can rely on Ethereum's security. Frequent transactions can use chains optimized for throughput. Domain-specific chains can handle specialized functionality. All of this works within a single application without per-chain integration overhead. ### For users Cross-chain operations become comparable in complexity to single-chain operations. The underlying routing, proof generation, and state verification happen at the protocol level rather than requiring manual steps from the user. ## Technical Components Agglayer coordinates several systems: * **Multiple cryptographic proof systems**: SP1 zkVM, Pessimistic Proofs, State Transition Proofs * **State synchronization** across connected chains * **Mathematical verification** of every cross-chain operation * **Hierarchical Merkle tree structures** (Local Exit Trees, Rollup Exit Tree, Global Exit Root) for efficient verification For detailed coverage of each component, see [Architecture](/interoperability/agglayer/core-concepts/architecture/), [Unified Bridge](/interoperability/agglayer/core-concepts/unified-bridge/), [Pessimistic Proof](/interoperability/agglayer/core-concepts/pessimistic-proof/), and [State Transition Proof](/interoperability/agglayer/core-concepts/state-transition-proof/). # Get Started Source: https://docs.polygon.technology/interoperability/agglayer/get-started/index Build cross-chain applications on AggLayer-connected CDK chains. ## Build Cross-Chain Applications on CDK AggLayer is built into every Chain Development Kit (CDK) chain. You can work with AggLayer's cross-chain capabilities in development and production without setting up separate interoperability infrastructure. ### What you can build on CDK chains * **Atomic cross-chain operations**: Execute operations across multiple chains in a single transaction * **Unified asset management**: Build applications where users' assets work across all supported chains * **Cross-chain smart contracts**: Create contracts that trigger actions and transfer value across different networks * **Multi-chain interfaces**: Build UIs that abstract chain selection away from the user ## Next steps * **[Supported chains](/interoperability/agglayer/supported-chains/)**: See which chains are connected to AggLayer, with RPC endpoints and chain IDs. * **[Integrations](/interoperability/agglayer/integrations/)**: Use Bridge Hub or the AggKit Bridge Service to query bridge data, generate claim proofs, and automate claiming across chains. # Overview Source: https://docs.polygon.technology/interoperability/agglayer/index Agglayer connects chains with shared liquidity, atomic cross-chain transactions, and cryptographic security. ## Overview Agglayer is Polygon's interoperability layer. It connects chains so assets can move without wrapping, operations can be atomic across chains, and security is enforced through cryptographic proofs rather than trusted parties. CDK chains connect to Agglayer by default. Other chains can integrate independently. **What Agglayer provides:** * **Unified liquidity**: Assets maintain their identity across connected chains. No wrapped tokens required. * **Atomic cross-chain operations**: Transactions either succeed on all involved chains or fail entirely — no partial states. * **Mathematical security**: Pessimistic proofs ensure a compromised chain cannot drain more than its own deposits. Damage is contained. * **Chain sovereignty**: Connected chains keep their own architecture and governance. Agglayer adds interoperability without requiring changes to how a chain operates. ## Explore Agglayer Understand how Agglayer works: the three security gateways, proof systems, and how chains connect to the network. Start building cross-chain applications on Agglayer-connected chains. APIs and services for integrating Agglayer bridge functionality into your applications. # API Reference Source: https://docs.polygon.technology/interoperability/agglayer/integrations/aggkit-bridge-service/api-reference REST API documentation for the AggKit Bridge Service: endpoints, parameters, and response formats. ## API Base URL All Bridge Service endpoints follow this structure: ``` {base_url}/bridge/v1/{endpoint} ``` ## Health & Status ### `GET /` - Service Health Check **Example Request:** ```bash theme={null} curl "http://localhost:5577/" ``` **Response:** ```json theme={null} { "status": "healthy", "version": "1.0.0", "network_id": 1, "uptime": "2h15m30s", "last_processed_block": 15234567 } ``` **Response Fields:** * `status`: Service health indicator * `version`: API version for compatibility checks * `network_id`: Primary network being served * `uptime`: Service runtime duration * `last_processed_block`: Latest indexed block number ### `GET /sync-status` - Component Synchronization Status **Example Request:** ```bash theme={null} curl "http://localhost:5577/bridge/v1/sync-status" ``` **Response:** ```json theme={null} { "l1_sync": { "current_block": 15234567, "synced_block": 15234560, "is_synced": true }, "l2_sync": { "current_block": 8765432, "synced_block": 8765432, "is_synced": true }, "bridge_sync": { "l1_bridges_indexed": 12345, "l2_bridges_indexed": 6789, "last_update": "2024-09-24T10:30:45Z" } } ``` ## Bridge Transaction Queries ### `GET /bridges` - Query Bridge Transactions **Parameters:** | Parameter | Type | Required | Description | Example | | --------------- | ------- | -------- | ------------------------------------ | ----------- | | `network_id` | integer | ✅ | Origin network ID (0=L1, 1=L2, etc.) | `0` | | `page_number` | integer | ❌ | Page number (default: 1) | `1` | | `page_size` | integer | ❌ | Page size (default: 100, max: 1000) | `10` | | `deposit_count` | integer | ❌ | Filter by specific deposit count | `42` | | `from_address` | string | ❌ | Filter by sender address | `0xf39F...` | | `network_ids` | array | ❌ | Filter by destination network IDs | `1,2` | **Example Request Patterns:** ```bash theme={null} # Get recent bridges for a user curl "http://localhost:5577/bridge/v1/bridges?network_id=0&from_address=0xf39F...&page_size=10" # Find specific transaction by deposit count curl "http://localhost:5577/bridge/v1/bridges?network_id=0&deposit_count=42" # Check ready-to-claim transactions curl "http://localhost:5577/bridge/v1/bridges?network_id=0&ready_for_claim=true" ``` **Response Structure:** ```json theme={null} { "bridges": [ { "tx_hash": "0x8d1b60d0eaab6f609955bdd371e8004f47349cc809ff1bee81dc9d37237a031c", "deposit_count": 42, "origin_network": 0, "destination_network": 1, "origin_address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "destination_address": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", "amount": "1000000000000000000", "block_timestamp": 1695563045, "ready_for_claim": true } ], "pagination": { "page": 1, "limit": 10, "total": 150 } } ``` **Key Response Fields:** * `tx_hash`: Bridge transaction identifier * `deposit_count`: Sequential index for proof generation * `amount`: Bridge amount in wei/token units * `ready_for_claim`: Whether transaction can be claimed * `block_timestamp`: When the bridge occurred ## Claim Tracking ### `GET /claims` - Query Claim Transactions **Key Parameters:** | Parameter | Type | Required | Description | | -------------- | ------- | -------- | ------------------------------- | | `network_id` | integer | ✅ | Network where claims occurred | | `from_address` | string | ❌ | Filter by claimer address | | `page_size` | integer | ❌ | Results per page (default: 100) | **Example Usage:** ```bash theme={null} # Check claims on a specific network curl "http://localhost:5577/bridge/v1/claims?network_id=1&page_size=10" # Find claims by specific user curl "http://localhost:5577/bridge/v1/claims?network_id=1&from_address=0x7099..." ``` **Response:** ```json theme={null} { "claims": [ { "tx_hash": "0xa9fa5418144f7c8c1b78cd0e5560d6550411667ef937b554636a613f933b3d9f", "global_index": "0x000000000000000000000000000000000000000000000000000000000000002a", "amount": "1000000000000000000", "block_timestamp": 1695563145, "bridge_tx_hash": "0x8d1b60d0eaab6f609955bdd371e8004f47349cc809ff1bee81dc9d37237a031c" } ] } ``` ## Proof Generation ### `GET /claim-proof` - Generate Claim Proof Generates the cryptographic proofs required to claim bridged assets. Pass the entire `proof` object returned to your claim contract function. **Required Parameters:** | Parameter | Type | Description | Example | | --------------- | ------- | ------------------------------------ | ------- | | `network_id` | integer | Origin network of bridge transaction | `0` | | `deposit_count` | integer | Deposit count from bridge event | `42` | | `leaf_index` | integer | L1 Info Tree index for proof | `15` | **Example Request:** ```bash theme={null} curl "http://localhost:5577/bridge/v1/claim-proof?network_id=0&deposit_count=42&leaf_index=15" ``` **Response Structure:** ```json theme={null} { "proof": { "smtProofLocalExitRoot": ["0x...", "0x...", "0x..."], "smtProofRollupExitRoot": ["0x...", "0x..."], "l1InfoTreeLeaf": { "globalExitRoot": "0x...", "blockNumber": 15234567, "timestamp": 1695563045 } } } ``` ## Additional Utilities ### `GET /l1-info-tree-index` - Get L1 Info Tree Index Returns the L1 Info Tree index required for the `leaf_index` parameter in `/claim-proof`. ```bash theme={null} curl "http://localhost:5577/bridge/v1/l1-info-tree-index?network_id=0&deposit_count=42" ``` **Response:** ```json theme={null} { "l1_info_tree_index": 15, "block_number": 15234567, "global_exit_root": "0x..." } ``` ### `GET /token-mappings` - Token Information Get token mapping information for cross-chain token relationships. **Use Case**: Display token information and cross-chain mappings in bridge interfaces. ```bash theme={null} curl "http://localhost:5577/bridge/v1/token-mappings" ``` ## Error Handling **Common Error Scenarios:** | Error Code | When It Happens | What To Do | | --------------------- | ---------------------------- | ----------------------------------------- | | `INVALID_NETWORK_ID` | Using unsupported network ID | Check supported networks via `/` endpoint | | `BRIDGE_NOT_FOUND` | Transaction not yet indexed | Wait for indexing to complete | | `PROOF_NOT_AVAILABLE` | L1 finality not reached | Wait for L1 confirmation | | `RATE_LIMIT_EXCEEDED` | Too many requests | Implement backoff and retry | **Example Error Response:** ```json theme={null} { "error": { "code": "INVALID_NETWORK_ID", "message": "Network ID 999 is not supported" } } ``` # AggKit Bridge Service Source: https://docs.polygon.technology/interoperability/agglayer/integrations/aggkit-bridge-service/index REST API for bridge data, transaction status, and proof generation without running AggKit infrastructure. **Source code:** [github.com/agglayer/aggkit](https://github.com/agglayer/aggkit) ## Overview The Bridge Service API is a REST API that provides access to bridge data from AggKit: transaction histories, claim statuses, cryptographic proofs, and network information. It exposes this data through simple HTTP endpoints, removing the need to run and maintain blockchain indexers or proof generation infrastructure. All endpoints follow the pattern: ``` {base_url}/bridge/v1/{endpoint} ``` No authentication is required for most operations. ## What the API provides * **Bridge transaction data**: Query bridge transactions by address, network, or transaction hash * **Claim status**: Check whether a bridge transaction is ready to claim * **Proof generation**: Retrieve the cryptographic proof required for claim transactions * **Network information**: Access bridge contract addresses and network configuration ## Quick start ```bash theme={null} # Check if the API is running curl "http://localhost:5577/bridge/v1/" # Get recent bridge transactions on a network curl "http://localhost:5577/bridge/v1/bridges?network_id=0&page_size=5" # Get bridges for a specific address curl "http://localhost:5577/bridge/v1/bridges?network_id=0&from_address=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" # Check for transactions ready to claim curl "http://localhost:5577/bridge/v1/bridges?network_id=0&from_address=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266&ready_for_claim=true" # Generate a claim proof curl "http://localhost:5577/bridge/v1/claim-proof?network_id=0&deposit_count=42&leaf_index=15" ``` ## Reference All endpoints, parameters, and response formats. # API Reference Source: https://docs.polygon.technology/interoperability/agglayer/integrations/bridge-hub/api-reference Bridge Hub REST API: endpoints, parameters, and response formats for querying bridge transactions. The Bridge Hub API exposes interactive OpenAPI documentation at the `/docs` endpoint. You can browse endpoints and test API calls directly in the browser. The Bridge Hub API is a read-only REST API. All endpoints use the `GET` method, and all responses are returned as `application/json`. ## GET /transactions Query bridge transactions with filtering and cursor-based pagination. ### Parameters | Parameter | Type | Required | Description | | ----------------------- | ------- | -------- | -------------------------------------------------------- | | `status` | string | No | Filter by status: `BRIDGED`, `READY_TO_CLAIM`, `CLAIMED` | | `sourceNetworkIds` | string | No | Comma-separated source network IDs | | `destinationNetworkIds` | string | No | Comma-separated destination network IDs | | `fromAddress` | string | No | Filter by sender address | | `receiverAddress` | string | No | Filter by receiver address | | `limit` | integer | No | Results per page (default: 50) | | `startAfter` | string | No | Cursor for pagination | ### Example request ```bash theme={null} curl "https://bridge-hub.example.com/transactions?status=READY_TO_CLAIM&limit=2" ``` ### Example response ```json theme={null} { "data": [ { "hubUID": "tx-0001", "sourceNetwork": 1, "destinationNetwork": 2442, "transactionHash": "0xabc123...", "blockNumber": 19500000, "timestamp": 1710000000, "leafType": "ASSET", "originTokenNetwork": 1, "originTokenAddress": "0x0000000000000000000000000000000000000000", "receiverAddress": "0xdef456...", "fromAddress": "0x789abc...", "amount": "1000000000000000000", "depositCount": 42, "leafIndexForProof": 42, "globalIndex": "42", "status": "READY_TO_CLAIM", "lastUpdatedAt": 1710000300, "claimTransactionHash": null, "claimBlockNumber": null, "claimTimestamp": null } ], "nextStartAfterCursor": "eyJsYXN0SWQiOiJ0eC0wMDAxIn0=" } ``` ### Response fields | Field | Type | Description | | ---------------------- | -------------- | ---------------------------------------------- | | `hubUID` | string | Unique business key for the transaction | | `sourceNetwork` | number | Source chain ID | | `destinationNetwork` | number | Destination chain ID | | `transactionHash` | string | Source transaction hash | | `blockNumber` | number | Block number on the source chain | | `timestamp` | number | Unix timestamp of the bridge event | | `leafType` | string | `ASSET` or `MESSAGE` | | `originTokenNetwork` | number | Network ID where the token originates | | `originTokenAddress` | string | Token contract address on the origin network | | `receiverAddress` | string | Address that will receive funds on destination | | `fromAddress` | string | Sender address on the source chain | | `amount` | string | Transfer amount (BigInt encoded as string) | | `depositCount` | number | Deposit counter from the bridge event | | `leafIndexForProof` | number | Leaf index in the merkle tree | | `globalIndex` | string | Global index (encoded as string) | | `status` | string | `BRIDGED`, `READY_TO_CLAIM`, or `CLAIMED` | | `lastUpdatedAt` | number | Unix timestamp of last status update | | `claimTransactionHash` | string or null | Claim transaction hash (populated after claim) | | `claimBlockNumber` | number or null | Block number of the claim transaction | | `claimTimestamp` | number or null | Unix timestamp of the claim | ## GET /claim-proof Generate a merkle proof for claiming a bridge transaction. This endpoint proxies to the source chain's AggKit Bridge Service to retrieve the proof data needed to submit a claim on the destination chain. ### Parameters | Parameter | Type | Required | Description | | ----------------- | ------- | -------- | --------------------------------- | | `sourceNetworkId` | integer | Yes | Source chain network ID | | `depositCount` | integer | Yes | Deposit counter from bridge event | | `leafIndex` | integer | Yes | Leaf index in merkle tree | ### Example request ```bash theme={null} curl "https://bridge-hub.example.com/claim-proof?sourceNetworkId=1&depositCount=42&leafIndex=42" ``` ### Example response ```json theme={null} { "proof_local_exit_root": ["0x...", "0x..."], "proof_rollup_exit_root": ["0x...", "0x..."], "l1_info_tree_leaf": { "l1InfoTreeIndex": 100, "rer": "0x...", "mer": "0x...", "innerBlock": 19500000, "innerTimestamp": 1710000000 }, "bridge_tx_metadata": "0x..." } ``` ### Response fields | Field | Type | Description | | ------------------------ | --------- | ------------------------------------------------- | | `proof_local_exit_root` | string\[] | Merkle proof siblings for the local exit root | | `proof_rollup_exit_root` | string\[] | Merkle proof siblings for the rollup exit root | | `l1_info_tree_leaf` | object | L1 info tree leaf data used in claim verification | | `bridge_tx_metadata` | string | Encoded metadata for the bridge transaction | ## GET /token-mappings Get token address mappings between networks. Returns the relationship between original token addresses and their wrapped counterparts on destination networks. ### Example request ```bash theme={null} curl "https://bridge-hub.example.com/token-mappings" ``` ### Example response ```json theme={null} { "data": [ { "originNetwork": 1, "originTokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "wrappedTokenAddress": "0x37eAA0eF3549a5bB7D431be78a3D99BD6fd6b57D", "destinationNetwork": 2442 } ] } ``` ## GET /token-metadata Get token metadata including name, symbol, and decimals for tokens tracked by Bridge Hub. ### Example request ```bash theme={null} curl "https://bridge-hub.example.com/token-metadata" ``` ### Example response ```json theme={null} { "data": [ { "tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "networkId": 1, "name": "USD Coin", "symbol": "USDC", "decimals": 6 } ] } ``` ## GET /health-check Returns the service health status. ### Example request ```bash theme={null} curl "https://bridge-hub.example.com/health-check" ``` ### Example response ```json theme={null} { "status": "success", "data": { "status": "success", "message": "All services are working correctly" } } ``` ## Pagination The Bridge Hub API uses cursor-based pagination for the `/transactions` endpoint. 1. Make an initial request with an optional `limit` parameter. 2. If more results exist, the response includes a `nextStartAfterCursor` value. 3. Pass that value as the `startAfter` parameter in your next request to retrieve the following page. ```bash theme={null} # First page curl "https://bridge-hub.example.com/transactions?limit=50" # Next page (using the cursor from the previous response) curl "https://bridge-hub.example.com/transactions?limit=50&startAfter=eyJsYXN0SWQiOiJ0eC0wMDUwIn0=" ``` Cursor-based pagination provides several benefits over offset-based approaches: * **Stable results.** Concurrent inserts or updates do not cause skipped or duplicated entries between pages. * **Consistent performance.** Fetching page 1,000 is as fast as fetching page 1, since the database seeks directly to the cursor position. * **No deep pagination issues.** There is no growing cost as you move further through the result set. ## Error handling The API uses standard HTTP status codes and returns structured error responses. ### Status codes | Code | Meaning | Description | | ---- | ------------ | ------------------------------------------ | | 200 | Success | Request completed successfully | | 400 | Bad Request | Invalid or missing query parameters | | 404 | Not Found | Requested resource does not exist | | 500 | Server Error | An unexpected error occurred on the server | ### Error response format All error responses follow a consistent structure: ```json theme={null} { "status": "error", "message": "Invalid query parameter: status must be one of BRIDGED, READY_TO_CLAIM, CLAIMED" } ``` Error messages describe the problem without exposing sensitive internal details. If you receive a `500` response, retry the request after a short delay. For persistent errors, check the `/health-check` endpoint to verify service availability. # Architecture Source: https://docs.polygon.technology/interoperability/agglayer/integrations/bridge-hub/architecture Bridge Hub system architecture: consumer internals, multi-network deployment, and database design. ## System architecture The Bridge Hub is a microservices-based system that monitors, indexes, exposes, and automatically claims cross-chain bridge transactions. It consists of four packages that work together around a shared MongoDB database. ``` ┌──────────────────────────────────────────────────────────────────┐ │ External Systems │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Aggkit │ │ Blockchain │ │ MongoDB │ │ │ │ Bridge │ │ │ │ Database │ │ │ │ service │ │ │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ └─────────┼─────────────────┼─────────────────┼────────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────────────────────────────────────────────────────┐ │ Bridge Hub Packages │ │ │ │ ┌───────────────┐ │ │ │ COMMONS │ │ │ │ (Shared Types)│ │ │ └───────┬───────┘ │ │ │ │ │ ┌─────────────┼─────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌──────────┐ ┌─────────┐ ┌───────────┐ │ │ │ CONSUMER │ │ API │ │AUTO-CLAIM │ │ │ │ (Indexer)│ │(Service)│ │(Claimer) │ │ │ └─────┬────┘ └────┬────┘ └─────┬─────┘ │ │ │ │ │ │ │ │ Writes │ Reads │ HTTP │ │ ▼ ▼ ▼ │ │ ┌──────────────────────────┐ ┌─────────────┐ │ │ │ MongoDB Database │ │ Blockchain │ │ │ └──────────────────────────┘ └─────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` The four packages serve distinct roles: | Package | Layer | Responsibility | | -------------- | -------------- | -------------------------------------------------------------------------------- | | **Commons** | Foundation | Shared TypeScript types, interfaces, and schemas used by all other packages | | **Consumer** | Data ingestion | Polls AggKit Bridge Service APIs to index bridge transactions into MongoDB | | **API** | Service | Exposes indexed transaction data and proxies claim proofs over a REST interface | | **Auto-Claim** | Automation | Polls the API for claimable transactions and submits claim transactions on-chain | **Commons** acts as the foundation layer. It contains pure TypeScript types with no runtime code, providing type-safe contracts that the other three packages depend on. **Consumer** writes data into MongoDB. **API** reads from the same database and serves it to clients. **Auto-Claim** consumes the API over HTTP and interacts with the blockchain to finalize claims. ## Consumer internals The Consumer package runs as a single Node.js process per network. It contains two components that together run four cron jobs. ### BridgeAPIConsumer This component runs three cron jobs that fetch data from the AggKit Bridge Service: 1. **bridgesCron**: Polls AggKit for new bridge deposit transactions. Each new deposit is inserted into the `transactions` collection with a status of `BRIDGED`. The cron tracks its progress by updating `lastIndexedBridgeDepositCount` in the metadata collection. 2. **claimsCron**: Polls AggKit for claim events that have occurred on-chain. When a claim is detected, the corresponding transaction is updated to `CLAIMED` and the `claimTransactionHash` and timestamp are recorded. Progress is tracked via `lastIndexedClaimBlockNumber`. 3. **mappingsCron**: Polls AggKit for token mapping events. New or updated mappings are upserted into the `mappings` collection. Progress is tracked via `lastIndexedMappingBlockNumber`. ### ClaimReadinessConsumer This component runs a single cron job: 4. **readyToClaimCron**: Checks the L1 info tree data from AggKit and compares it against transactions that are currently in `BRIDGED` status. When a transaction becomes claimable, the cron updates it to `READY_TO_CLAIM` and sets the `leafIndexForProof` field needed for merkle proof generation. ### Consumer data flow ``` Aggkit Bridge Service (per network) │ ├── /bridges API ────▶ bridgesCron ────▶ transactions collection (BRIDGED) │ ├── /claims API ─────▶ claimsCron ─────▶ transactions collection (CLAIMED) │ ├── /mappings API ───▶ mappingsCron ───▶ mappings collection │ └── /l1-info-tree ───▶ readyToClaimCron ▶ transactions collection (READY_TO_CLAIM) ``` All four cron jobs run at configured intervals within the same process. The metadata collection tracks each cron's indexing checkpoint so the consumer can resume from the correct position after a restart. ## Multi-network deployment In production, the Bridge Hub runs **one consumer instance per source network** being indexed. Each network connected to the AggLayer has a unique network ID (for example, 0 for Ethereum, 1 for Polygon zkEVM). A single shared API service reads from the database and serves all networks, while one auto-claim instance runs per destination network. The consumer does **not** directly monitor the blockchain. It polls the AggKit Bridge Service APIs to fetch already-indexed data. Each chain's AggKit Bridge Service is maintained by the chain operators and is external to the Bridge Hub deployment. ``` ┌──────────────────────────────────────────────────────────────────────────────┐ │ AGGLAYER HUB API CLUSTER │ ├──────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────────────────────────┐ │ │ │ Aggkit │ │ netId_0 Consumer │ │ │ │ Bridge │──────▶ │ ┌───────────────────────────┐ │ │ │ │ Service │ │ │ bridgesCron │ │ │ │ │ (net 0) │ │ │ claimsCron │ │──┐ │ │ └─────────────┘ │ │ readyToClaimCron │ │ │ │ │ │ │ mappingsCron │ │ │ │ │ │ └───────────────────────────┘ │ │ │ │ └─────────────────────────────────┘ │ │ │ │ │ │ ┌─────────────┐ ┌─────────────────────────────────┐ │ │ │ │ Aggkit │ │ netId_1 Consumer │ │ │ │ │ Bridge │──────▶ │ ┌───────────────────────────┐ │ │ │ │ │ Service │ │ │ bridgesCron │ │ │ │ │ │ (net 1) │ │ │ claimsCron │ │──┤ │ │ └─────────────┘ │ │ readyToClaimCron │ │ │ │ │ │ │ mappingsCron │ │ │ │ │ │ └───────────────────────────┘ │ │ │ │ └─────────────────────────────────┘ │ │ │ │ │ │ ┌─────────────┐ ┌─────────────────────────────────┐ │ │ │ │ Aggkit │ │ netId_n Consumer │ │ │ │ │ Bridge │──────▶ │ ┌───────────────────────────┐ │ │ │ │ │ Service │ │ │ bridgesCron │ │ │ │ │ │ (net n) │ │ │ claimsCron │ │──┤ │ │ └─────────────┘ │ │ readyToClaimCron │ │ │ │ │ │ │ mappingsCron │ │ │ │ │ │ └───────────────────────────┘ │ │ │ │ └─────────────────────────────────┘ │ │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────────────┐ │ │ │ MongoDB Database │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ │ Collections (per environment): │ │ │ │ │ │ • bridge_hub_api_transactions │ │ │ │ │ │ • bridge_hub_api_mappings │ │ │ │ │ │ • bridge_hub_api_metadata │ │ │ │ │ └──────────────────────────────────────┘ │ │ │ └────────────┬───────────────────────────────┘ │ │ │ │ │ ▼ Reads from │ │ ┌────────────────────────────────────────────┐ │ │ │ API Service │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ │ /transactions │ │ │ │ │ │ /token-mappings │ │ │ │ │ │ /token-metadata │ │ │ │ │ │ /claim-proof (proxies to Aggkit) │ │───┐ │ │ │ └──────────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────────┘ │ │ │ │ │ │ HTTP Calls │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ │ Auto-Claim Service (per dest network) │◀─┘ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ │ Polls /transactions │ │ │ │ │ │ Fetches /claim-proof │ │ │ │ │ │ Submits claims to blockchain │ │ │ │ │ └──────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ ``` Key deployment points: * **Consumer instances**: One per source network being indexed (`netId_0`, `netId_1`, and so on). * **Shared database**: All consumers write to the same MongoDB instance. * **Single API**: One API service reads from the database and serves all networks. * **Auto-Claim deployment**: One instance per destination network you want to auto-claim for. ## Database design Bridge Hub uses a single shared MongoDB instance. Collections are organized by environment using the naming convention `bridge_hub_api_[type]_[environment]`, where the environment suffix is omitted for mainnet, `_testnet` for testnet, and `_devnet` for development. ### Collections The database contains three collection types: 1. **transactions**: Stores all bridge transactions across all networks. Modified by `bridgesCron` (upserts), `claimsCron` (status updates), and `readyToClaimCron` (status updates). Transactions move through the statuses `BRIDGED`, `LEAF_INCLUDED`, `READY_TO_CLAIM`, and `CLAIMED`. 2. **mappings**: Stores token address mappings between AggLayer networks. Modified by `mappingsCron`. Each record maps an origin token address on one network to its wrapped token address on another. 3. **metadata**: Tracks indexing progress per network. Each cron job updates its own checkpoint field in this collection. One document exists per network ID being indexed. ### Transaction document schema ```javascript theme={null} { _id: ObjectId, // MongoDB primary key hubUID: String (unique), // Business key // Network Information sourceNetwork: Number, // Source chain ID destinationNetwork: Number, // Destination chain ID // Transaction Details transactionHash: String, // Source transaction hash blockNumber: Number, // Block number on source timestamp: Number, // Unix timestamp bridgeHash: String, // Bridge Details leafType: String, // "ASSET" or "MESSAGE" originTokenNetwork: Number, originTokenAddress: String, receiverAddress: String, fromAddress: String, amount: String, // BigInt as string depositCount: Number, // Deposit counter // Claiming Details leafIndexForProof: Number, // Index for merkle proof globalIndex: String, // Global index as string // Status Tracking status: String, // BRIDGED, LEAF_INCLUDED, READY_TO_CLAIM, CLAIMED lastUpdatedAt: Number, // Last update timestamp // Claim Information (populated after claim) claimTransactionHash: String, claimBlockNumber: Number, claimTimestamp: Number } ``` ### Indexes ```javascript theme={null} { hubUID: 1 // Unique index status: 1, // Query by status { sourceNetwork: 1, destinationNetwork: 1 }, // Filter by networks depositCount: 1, // Order by deposit count { status: 1, destinationNetwork: 1 } // Combined index for common queries } ``` ### Metadata and resume capability The metadata collection is critical for operational resilience. When a consumer instance restarts after a crash, planned maintenance, or redeployment, it reads its metadata document to find the last indexed position for each cron job. Without this checkpoint data, the consumer would need to re-index from the beginning, duplicating hours or days of work. Each metadata document tracks three resume points: * `lastIndexedBridgeDepositCount`: where `bridgesCron` should resume * `lastIndexedClaimBlockNumber`: where `claimsCron` should resume * `lastIndexedMappingBlockNumber`: where `mappingsCron` should resume On startup, each cron reads its respective checkpoint and picks up exactly where it left off. ## Data synchronization The system maintains eventual consistency through three distinct data paths: * **Write path** (Consumer to MongoDB): Consumers poll AggKit APIs and write new or updated records into MongoDB. All writes use upsert operations, making them idempotent. Duplicate events from AggKit are handled gracefully. * **Read path** (API from MongoDB): The API service reads directly from MongoDB and serves the data over REST endpoints. Because the API is stateless and read-only, it can be scaled horizontally behind a load balancer. * **Claim path** (Auto-Claim to Blockchain): The Auto-Claim service polls the API for transactions in `READY_TO_CLAIM` status, fetches merkle proofs through the API's `/claim-proof` endpoint, and submits claim transactions on-chain. Claims are processed sequentially to avoid nonce conflicts. ### Consistency guarantees * Transactions are immutable once created; only status fields are updated. * Status updates are atomic at the document level. * Duplicate events are handled via upsert, so re-processing the same data is safe. * No distributed transactions are needed because all state lives in a single MongoDB instance. * There is a small window of delay between an on-chain event occurring and the consumer indexing it. During this window, the API may serve slightly stale data. This is acceptable for the bridge use case, where transactions take time to become claimable regardless. # Auto-Claim Service Source: https://docs.polygon.technology/interoperability/agglayer/integrations/bridge-hub/auto-claim Automated bridge transaction claiming: configuration, deployment, and security. ## Overview The auto-claim service automates the claiming of bridge transactions on the destination chain. It polls the Bridge Hub API for transactions in `READY_TO_CLAIM` status, fetches Merkle proofs, and submits claim transactions. It handles both `ASSET` and `MESSAGE` claim types and filters out zero-amount `MESSAGE` transactions. ## How it works The auto-claim service runs a continuous polling loop on a 30-second interval. Each cycle follows this sequence: 1. Poll the Bridge Hub API for transactions with `READY_TO_CLAIM` status. 2. Filter the returned transactions by source network and claim type. 3. For each transaction: fetch the Merkle proof, compute the global index, submit the claim transaction, and wait for on-chain confirmation. 4. Sleep for 30 seconds, then repeat. ``` ┌─────────────────┐ │ Poll API │ │ (30s interval) │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Filter Txs │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ For Each Tx: │ │ 1. Get Proof │ │ 2. Compute Index│ │ 3. Submit Claim │ │ 4. Wait Confirm │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Sleep 30s │ └────────┬────────┘ │ └──────→ (repeat) ``` Claims are processed sequentially to avoid nonce conflicts. One auto-claim instance should run per destination network. Errors on one transaction do not affect others. The blockchain enforces claim uniqueness, so the service is safe to restart at any time without risk of double-claiming. Failed claim transactions are reverted on-chain and do not result in lost funds. ## Configuration The auto-claim service is configured through environment variables. | Variable | Required | Example | Description | | ----------------------------- | -------- | --------------------------- | ---------------------------------------- | | `BRIDGE_HUB_API_URL` | Yes | `http://api:3000` | Bridge Hub API URL | | `SOURCE_NETWORKS` | Yes | `[1,137]` | Source network IDs (JSON array) | | `DESTINATION_NETWORK` | Yes | `2442` | Destination network ID | | `DESTINATION_NETWORK_CHAINID` | Yes | `2442` | Destination chain ID | | `BRIDGE_CONTRACT` | Yes | `0x...` | Bridge contract address | | `PRIVATE_KEY` | Yes | `0x...` | Wallet private key for submitting claims | | `RPC_CONFIG` | Yes | `{"2442":"https://..."}` | RPC endpoints (JSON object) | | `SENTRY_DSN` | No | `https://...@sentry.io/...` | Error tracking DSN | ## Deployment Deploy one auto-claim instance for each destination network you want to auto-claim for. ### Docker Compose Add the following service to your `docker-compose.yml`: ```yaml theme={null} autoclaim: build: context: . dockerfile: Dockerfile.autoclaim environment: NODE_ENV: production BRIDGE_HUB_API_URL: http://api:3001 SOURCE_NETWORKS: ${SOURCE_NETWORKS} DESTINATION_NETWORK: ${DESTINATION_NETWORK} DESTINATION_NETWORK_CHAINID: ${DESTINATION_NETWORK_CHAINID} BRIDGE_CONTRACT: ${BRIDGE_CONTRACT} PRIVATE_KEY: ${PRIVATE_KEY} RPC_CONFIG: ${RPC_CONFIG} SENTRY_DSN: ${SENTRY_DSN} depends_on: - api restart: unless-stopped networks: - bridge-hub ``` ### Direct execution with Bun You can also run the service directly: ```bash theme={null} # Auto-claim for destination network 2442 BRIDGE_HUB_API_URL=http://localhost:3001 \ DESTINATION_NETWORK=2442 \ DESTINATION_NETWORK_CHAINID=2442 \ SOURCE_NETWORKS=[0,1,137] \ BRIDGE_CONTRACT=0x... \ PRIVATE_KEY=0x... \ RPC_CONFIG='{"2442":"https://rpc.example.com"}' \ bun start ``` To auto-claim for multiple destination networks, run a separate instance for each: ```bash theme={null} # Instance 1: destination 2442 DESTINATION_NETWORK=2442 DESTINATION_NETWORK_CHAINID=2442 bun start # Instance 2: destination 1101 DESTINATION_NETWORK=1101 DESTINATION_NETWORK_CHAINID=1101 bun start ``` ## Security The auto-claim service requires a private key to submit on-chain transactions. Follow these guidelines to protect it: * **Never log or expose private keys.** Ensure your logging configuration does not capture environment variables. * **Load keys from a secret management system** such as AWS Secrets Manager, HashiCorp Vault, or Kubernetes Secrets. Avoid hardcoding keys in configuration files. * **Use a dedicated wallet with minimal funding.** The wallet only needs enough native tokens to cover gas on the destination chain. * **Monitor for unusual activity.** Set up alerts for unexpected balance changes or transaction patterns on the claiming wallet. Claims are atomic: they either succeed or revert entirely. The blockchain enforces uniqueness, so a transaction cannot be claimed twice even if the service processes it again after a restart. ## Troubleshooting | Problem | Solution | | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | Transactions stuck in `READY_TO_CLAIM` | Check that the claiming wallet has sufficient gas on the destination chain. | | "API unreachable" errors | Verify `BRIDGE_HUB_API_URL` is correct and accessible from the auto-claim service. | | Nonce conflicts | Ensure only one auto-claim instance runs per destination network. | | Claims failing | Check RPC endpoint connectivity. Verify the `BRIDGE_CONTRACT` address is correct for the destination network. | # Deployment Source: https://docs.polygon.technology/interoperability/agglayer/integrations/bridge-hub/deployment Deploy Bridge Hub to production: Docker, Kubernetes, configuration, and troubleshooting. ## Prerequisites ### Infrastructure requirements Each Bridge Hub component has specific compute requirements: | Component | CPU | RAM | Notes | | ---------- | ------- | ---- | --------------- | | API | 2+ vCPU | 4 GB | Per instance | | Consumer | 2+ vCPU | 4 GB | Per network | | Auto-Claim | 1+ vCPU | 2 GB | Per destination | You also need a MongoDB instance (version 4.4 or later). A 3-node replica set is recommended for production, with at least 100 GB of storage that can grow with transaction volume. ### Software requirements * **Bun** >= 1.0.0 * **MongoDB** >= 4.4 * **Docker** (optional; for containerized deployment) * **Kubernetes** (optional; for orchestrated deployment) ### External services * **Bridge Service API** access for each network you plan to index. * **Blockchain RPC endpoints** from a reliable provider. * **Sentry account** (optional) for error tracking. ## Build From the repository root, install dependencies and create production builds: ```bash theme={null} bun install bun run build ``` This outputs production artifacts to `packages/api/dist/`, `packages/consumer/dist/`, and `packages/auto-claim/dist/`. ## Docker deployment The repository includes production-ready Dockerfiles for each service: * `Dockerfile.api`:API service (exposes port 3001) * `Dockerfile.consumer`:Consumer service * `Dockerfile.autoclaim`:Auto-Claim service Each Dockerfile uses `oven/bun:1.2-alpine` with multi-stage builds and runs as a non-root user (`bunuser`). ### Build images ```bash theme={null} docker build -f Dockerfile.api -t bridge-hub-api:latest . docker build -f Dockerfile.consumer -t bridge-hub-consumer:latest . docker build -f Dockerfile.autoclaim -t bridge-hub-autoclaim:latest . ``` ### Docker Compose Create a `docker-compose.yml` in the repository root: ```yaml theme={null} version: "3.8" services: mongodb: image: mongo:7 volumes: - mongo-data:/data/db environment: MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER} MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD} ports: - "27017:27017" restart: unless-stopped networks: - bridge-hub api: build: context: . dockerfile: Dockerfile.api ports: - "3001:3001" environment: NODE_ENV: production MONGODB_CONNECTION_URI: ${MONGODB_CONNECTION_URI} MONGODB_DB_NAME: ${MONGODB_DB_NAME} PROOF_CONFIG: ${PROOF_CONFIG} RPC_CONFIG: ${RPC_CONFIG} SENTRY_DSN: ${SENTRY_DSN} depends_on: - mongodb restart: unless-stopped networks: - bridge-hub consumer-net1: build: context: . dockerfile: Dockerfile.consumer environment: NODE_ENV: production NETWORK_ID: ${CONSUMER_NETWORK_ID} NETWORK: ${CONSUMER_NETWORK} BRIDGE_SERVICE_URL: ${BRIDGE_SERVICE_URL} BRIDGE_CONTRACT_ADDRESS: ${BRIDGE_CONTRACT_ADDRESS} MONGODB_CONNECTION_URI: ${MONGODB_CONNECTION_URI} MONGODB_DB_NAME: ${MONGODB_DB_NAME} SENTRY_DSN: ${SENTRY_DSN} depends_on: - mongodb restart: unless-stopped networks: - bridge-hub autoclaim: build: context: . dockerfile: Dockerfile.autoclaim environment: NODE_ENV: production BRIDGE_HUB_API_URL: http://api:3001 SOURCE_NETWORKS: ${SOURCE_NETWORKS} DESTINATION_NETWORK: ${DESTINATION_NETWORK} DESTINATION_NETWORK_CHAINID: ${DESTINATION_NETWORK_CHAINID} BRIDGE_CONTRACT: ${BRIDGE_CONTRACT} PRIVATE_KEY: ${PRIVATE_KEY} RPC_CONFIG: ${RPC_CONFIG} SENTRY_DSN: ${SENTRY_DSN} depends_on: - api restart: unless-stopped networks: - bridge-hub volumes: mongo-data: networks: bridge-hub: driver: bridge ``` ### Adding consumer instances for additional networks To index more than one network, duplicate the `consumer-net1` block with a unique service name and network-specific environment variables. For example: ```yaml theme={null} consumer-net137: build: context: . dockerfile: Dockerfile.consumer environment: NETWORK_ID: 137 NETWORK: mainnet BRIDGE_SERVICE_URL: ${BRIDGE_SERVICE_URL_NET137} BRIDGE_CONTRACT_ADDRESS: ${BRIDGE_CONTRACT_ADDRESS_NET137} MONGODB_CONNECTION_URI: ${MONGODB_CONNECTION_URI} MONGODB_DB_NAME: ${MONGODB_DB_NAME} depends_on: - mongodb restart: unless-stopped networks: - bridge-hub ``` ### Common Docker Compose commands ```bash theme={null} # Start all services in the background docker-compose up -d # Follow logs from all services docker-compose logs -f # Follow logs from a specific service docker-compose logs -f api # Check service status docker-compose ps # Restart a single service docker-compose restart api # Stop all services docker-compose down ``` ## Kubernetes deployment ### Namespace and ConfigMap ```yaml theme={null} apiVersion: v1 kind: Namespace metadata: name: bridge-hub --- apiVersion: v1 kind: ConfigMap metadata: name: bridge-hub-config namespace: bridge-hub data: MONGODB_DB_NAME: "bridge_hub" NODE_ENV: "production" ``` ### API Deployment ```yaml theme={null} apiVersion: apps/v1 kind: Deployment metadata: name: bridge-hub-api namespace: bridge-hub spec: replicas: 3 selector: matchLabels: app: bridge-hub-api template: metadata: labels: app: bridge-hub-api spec: containers: - name: api image: bridge-hub-api:latest ports: - containerPort: 3000 env: - name: MONGODB_CONNECTION_URI valueFrom: secretKeyRef: name: bridge-hub-secrets key: mongodb-uri - name: MONGODB_DB_NAME valueFrom: configMapKeyRef: name: bridge-hub-config key: MONGODB_DB_NAME resources: requests: memory: "2Gi" cpu: "1000m" limits: memory: "4Gi" cpu: "2000m" livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 5 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: bridge-hub-api namespace: bridge-hub spec: selector: app: bridge-hub-api ports: - port: 80 targetPort: 3000 type: LoadBalancer ``` ### Apply and manage resources ```bash theme={null} # Apply all manifests kubectl apply -f k8s/namespace.yaml kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/secrets.yaml kubectl apply -f k8s/api-deployment.yaml kubectl apply -f k8s/consumer-deployment.yaml kubectl apply -f k8s/auto-claim-deployment.yaml # Check pod status kubectl get pods -n bridge-hub # Follow API logs kubectl logs -f -n bridge-hub deployment/bridge-hub-api # Scale the API horizontally kubectl scale deployment bridge-hub-api --replicas=5 -n bridge-hub ``` ## Configuration reference Never commit secrets to the repository. Use a secret management system such as AWS Secrets Manager, HashiCorp Vault, or Kubernetes Secrets. ### API package | Variable | Required | Example | Description | | ------------------------ | -------- | --------------------------------- | -------------------------- | | `MONGODB_CONNECTION_URI` | Yes | `mongodb://user:pass@host:27017` | MongoDB connection string | | `MONGODB_DB_NAME` | Yes | `bridge_hub` | Database name | | `RPC_CONFIG` | Yes | `{"mainnet":{"1":"https://..."}}` | RPC endpoints by network | | `PROOF_CONFIG` | Yes | `{"mainnet":{"1":"https://..."}}` | Proof generation endpoints | | `PORT` | No | `3000` | HTTP port (default: 3000) | | `NODE_ENV` | No | `production` | Environment mode | | `SENTRY_DSN` | No | `https://...@sentry.io/...` | Error tracking DSN | ### Consumer package | Variable | Required | Example | Description | | --------------------------- | -------- | --------------------------------------- | ------------------------------------- | | `NETWORK_ID` | Yes | `1` | Network identifier | | `NETWORK` | Yes | `mainnet` | Network name (mainnet/testnet/devnet) | | `BRIDGE_SERVICE_URL` | Yes | `https://bridge-api.polygon.technology` | Bridge Service API URL | | `BRIDGE_CONTRACT_ADDRESS` | Yes | `0x...` | Bridge contract address | | `MONGODB_CONNECTION_URI` | Yes | `mongodb://user:pass@host:27017` | MongoDB connection string | | `MONGODB_DB_NAME` | Yes | `bridge_hub` | Database name | | `ETROG_UPDATE_BLOCK_NUMBER` | No | `0` | Starting block for indexing | | `SENTRY_DSN` | No | `https://...@sentry.io/...` | Error tracking DSN | ### Auto-Claim package | Variable | Required | Example | Description | | ----------------------------- | -------- | --------------------------- | -------------------------------- | | `BRIDGE_HUB_API_URL` | Yes | `http://api:3000` | Bridge Hub API URL | | `SOURCE_NETWORKS` | Yes | `[1,137]` | Source network IDs (JSON array) | | `DESTINATION_NETWORK` | Yes | `2442` | Destination network ID | | `DESTINATION_NETWORK_CHAINID` | Yes | `2442` | Destination chain ID | | `BRIDGE_CONTRACT` | Yes | `0x...` | Bridge contract address | | `PRIVATE_KEY` | Yes | `0x...` | Wallet private key for gas funds | | `RPC_CONFIG` | Yes | `{"2442":"https://..."}` | RPC endpoints (JSON) | | `SENTRY_DSN` | No | `https://...@sentry.io/...` | Error tracking DSN | ## Adding a new network Start a new consumer with the network's configuration: ```bash theme={null} NETWORK_ID=42161 \ NETWORK=mainnet \ BRIDGE_CONTRACT_ADDRESS=0x... \ BRIDGE_SERVICE_URL=https://aggkit-42161.example.com \ MONGODB_CONNECTION_URI=mongodb://... \ bun start ``` In Docker Compose, add a new `consumer-net` service block. In Kubernetes, create a new Consumer Deployment manifest. Add the new network's RPC endpoint to `RPC_CONFIG` and its proof endpoint to `PROOF_CONFIG`, then restart the API instances so they pick up the change. Append the new network ID to the `SOURCE_NETWORKS` JSON array, then restart Auto-Claim instances. Confirm the pipeline is working end to end: * **Consumer indexing**: Query the MongoDB metadata collection for the new network's checkpoint. * **API serving data**: Call `GET /transactions?sourceNetworkIds=42161` and confirm results appear. * **Auto-Claim detection**: Monitor Auto-Claim logs to verify it picks up new transactions. ## Troubleshooting | Symptom | Likely cause | Solution | | --------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Services crash with MongoDB connection errors | MongoDB is unreachable or credentials are wrong | Verify MongoDB is running (`mongosh $MONGODB_CONNECTION_URI`). Check network connectivity with `telnet mongo-host 27017`. Review credentials in your environment variables. | | API queries return no data | Consumer is not running or has not indexed yet | Confirm the Consumer process is active. Check that MongoDB contains documents (`db.transactions.count()`). Review API logs for errors and verify your query parameters. | | Transactions stuck in `READY_TO_CLAIM` | Auto-Claim cannot submit transactions | Check that the wallet has sufficient gas on the destination chain. Verify `BRIDGE_HUB_API_URL` is reachable from the Auto-Claim service. Test RPC endpoint connectivity. Confirm the private key is correct. | | Excessive memory usage | Unbounded batch sizes or tight poll intervals | Review Consumer batch size settings and increase poll intervals. Add memory limits in Docker or Kubernetes resource specs. Check logs for memory leak indicators. | # Bridge Hub Source: https://docs.polygon.technology/interoperability/agglayer/integrations/bridge-hub/index Multi-chain bridge transaction indexing, API, and auto-claim system for AggLayer integrators. ## Overview Bridge Hub is a multi-chain indexing and claiming system for AggLayer bridge transactions. It polls each chain's AggKit Bridge Service, indexes transaction data into MongoDB, and exposes the results through a unified REST API. Bridge Hub is designed for integrators who need a single interface to query and manage bridge transactions across all chains connected to the AggLayer. ## Bridge Hub vs. AggKit Bridge Service | | AggKit Bridge Service | Bridge Hub | | --------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | **Scope** | Single chain | Multi-chain | | **Runs on** | Chain operator infrastructure | Integrator infrastructure | | **Persistence** | In-memory | MongoDB | | **Exposes** | Raw bridge data | Indexed data + auto-claim | | **Components** | 1 service | 4 packages | | **Repo** | [agglayer/agglayer-rs](https://github.com/agglayer/agglayer-rs) | [0xPolygon/agglayer-bridge-hub-api](https://github.com/0xPolygon/agglayer-bridge-hub-api) | | **Audience** | Chain operators | dApp developers, bridge UIs, integrators | ## Data flow CDK chain → AggKit Bridge Service → Bridge Hub Consumer → Bridge Hub API → Bridge UI / Auto-Claim ## Packages | Package | Layer | Description | | -------------- | -------------- | ----------------------------------------------------------------------------------------- | | **Commons** | Foundation | Shared TypeScript types, interfaces, and schema definitions used across all packages | | **Consumer** | Data ingestion | Polls AggKit Bridge Service APIs per chain and writes transaction data to MongoDB | | **API** | Service | REST API with OpenAPI documentation for querying transactions and generating claim proofs | | **Auto-Claim** | Automation | Polls the API for claimable transactions and submits claim transactions on-chain | ## Transaction lifecycle A user initiates a bridge transaction on the source chain. The Consumer detects the deposit through the AggKit Bridge Service and saves the transaction to MongoDB with status `BRIDGED`. The Consumer monitors L1 info tree updates and determines when the transaction becomes claimable. It updates the transaction status to `READY_TO_CLAIM` and sets the leaf index needed for proof generation. The Auto-Claim service (or an external caller) fetches a merkle proof from the API and submits a claim transaction on the destination chain. Once confirmed, the Consumer detects the claim event and updates the status to `CLAIMED`. ## Technology stack * [Bun](https://bun.sh): JavaScript runtime * [Hono](https://hono.dev): Web framework for the REST API * [viem](https://viem.sh): TypeScript Ethereum library for blockchain interactions * [MongoDB](https://www.mongodb.com/): Document database for transaction storage * [Lerna](https://lerna.js.org/): Monorepo package management ## Next steps System design, consumer internals, and database schema. Configuration, environment variables, and production setup. REST endpoints, request parameters, and response schemas. Automated claiming service setup and operation. # Integrations Source: https://docs.polygon.technology/interoperability/agglayer/integrations/index Tools and APIs for integrating with AggLayer bridge infrastructure. ## Integrations Agglayer provides APIs and services for integrating cross-chain bridge functionality into your applications. Multi-chain bridge transaction indexer and API. Aggregates data from all connected chains into a single queryable interface with auto-claim support. REST API for accessing bridge data, transaction status, and proof generation without running infrastructure. # Supported Chains Source: https://docs.polygon.technology/interoperability/agglayer/supported-chains Chains connected to AggLayer: chain IDs, rollup IDs, RPC endpoints, block explorers, and gas tokens. ## Overview The following chains are connected to AggLayer. Each chain has a unique rollup ID assigned during registration. Chain types: * **PP (Pessimistic Proof)**: Sovereign mode secured by pessimistic proofs. No ZK prover required. * **Validium**: ZK-secured execution with offchain data availability. * **zkEVM**: Fully onchain ZK rollup. * **ALGateway**: Connected through the AggLayer Gateway. * **Outpost**: Non-CDK chain connected to AggLayer. ## Mainnets | Chain | Chain ID | Rollup ID | Type | Gas Token | RPC | Explorer | | ---------------------------------------------------------------------------------- | -------- | --------- | --------- | --------- | ------------------------------------------ | --------------------------------------------------------------------- | | [Ethereum](https://ethereum.org) | 1 | 0 | L1 | ETH | `https://eth.llamarpc.com` | [etherscan.io](https://etherscan.io) | | [Katana](https://docs.katana.network/) | 747474 | 20 | ALGateway | ETH | `https://rpc.katanarpc.com` | [katanascan.com](https://katanascan.com/) | | [Pentagon Games](https://pentagon.games/) | 3344 | 16 | Validium | PC | `https://rpc.pentagon.games` | [explorer.pentagon.games](https://explorer.pentagon.games/) | | [Silicon.network](https://docs.silicon.network) | 2355 | 10 | Validium | ETH | `https://rpc.silicon.network` | [scope.silicon.network](https://scope.silicon.network) | | [X Layer](https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/about-xlayer) | 196 | 3 | PP | OKB | `https://rpc.xlayer.tech` | [oklink.com/x-layer](https://www.oklink.com/x-layer) | | [Ternoa](https://docs.ternoa.network) | 752025 | 13 | zkEVM | CAPS | `https://rpc-mainnet.zkevm.ternoa.network` | [explorer.ternoa.com](https://explorer.ternoa.com/) | | [Wirex Pay](https://partner.wirexpaychain.com/docs/getting-started) | 31415 | 8 | zkEVM | ETH | `https://rpc.wirexpaychain.com` | [blockscout.wirexpaychain.com](https://blockscout.wirexpaychain.com/) | ## Testnets | Chain | Chain ID | Rollup ID | Type | Gas Token | RPC | Explorer | | ------------------------------------- | ---------- | --------- | --------- | --------- | ---------------------------------- | ------------------------------------------------------------------------------------------ | | [Bokuto](https://docs.katana.network) | 737373 | 37 | ALGateway | ETH | `https://rpc-bokuto.katanarpc.com` | [tenderly.co/explorer/katana-bokuto](https://dashboard.tenderly.co/explorer/katana-bokuto) | | [Lumia](https://docs.lumia.org/) | 2030232745 | 35 | zkEVM | LUMIA | `https://beam-rpc.lumia.org` | [beam-explorer.lumia.org](https://beam-explorer.lumia.org/) | # What is the Open Money Stack? Source: https://docs.polygon.technology/oms/overview One open stack for global money movement: fiat access, wallets, compliance, routing, and settlement in one vertically integrated, open platform. The Open Money Stack is Polygon's open, end-to-end infrastructure for global money movement. It connects fiat access, wallets, compliance, routing, and settlement into one integration, designed to plug into existing systems and move money in seconds. Need regulated rails, custodial infrastructure, compliance services, or a managed chain deployment? [Contact Polygon](https://info.polygon.technology/get-early-access). ## The problem with fragmented stacks Money should move reliably, at low cost. That requires predictable settlement without surprise deductions or delays. Most institutions building stablecoin payment flows today take the same path: choose a compliance vendor, a wallet provider, a bridge, an off-ramp, and a chain. When they have what they like, they stitch these solutions together. Each integration requires independent maintenance. In practice, this works, right up to the moment that volume grows or something goes wrong. Then teams must debug an outage that lives somewhere between three vendors and a dozen systems. ## A different architecture The Open Money Stack is **open and vertically integrated**: every layer is built to hand off cleanly to the next, with no lock-in. And it's composable. If an institution only wants to use one aspect of the Open Money Stack, say Polygon Chain for settlement or just the wallet infrastructure, they can pick and choose. **Use all of it, or only the components you need.** ## Settlement at the bottom of the stack Most payments orchestration companies don't own the infrastructure they route on. They aggregate across vendors they don't control, adding margin at every layer. When settlement breaks, they call their vendor. Polygon owns the settlement layer. The OMS is built on Polygon Chain: not as a dependency, but as infrastructure Polygon operates. **\$54B in stablecoin transfer volume**, **159M unique wallet addresses**, **6.4B total transactions**, and an average transaction cost of **\$0.002**, with live integrations by Revolut, Stripe, Flutterwave, and more. The economics compound at scale: costs improve as volume grows, rather than degrading through intermediary margin stacking. ## Unrolling the stack 1-click wallet creation with zero-config auth, passkeys, Smart Sessions, and enterprise-grade security. Custodial and non-custodial options both supported. Licensed fiat on- and off-ramps covering bank transfer, debit card, and cash at 50,000+ retail locations. KYC, AML, and compliance built in. 1-click transactions on any chain with any token. Deep unified liquidity across every connected network, with routing and bridging handled automatically. Polygon Chain for public settlement and Polygon Chain Development Kit (CDK) for dedicated rollup rails with 20,000+ TPS, compliance controls, and native Agglayer connectivity. Enterprise payments infrastructure for stablecoins and tokenized deposits. Native USDC with no wrapping, no bridges, and no hidden deductions. x402 for pay-per-use APIs. ERC-8004 for onchain agent identity. Infrastructure for autonomous agent commerce without human approval at every step. ## Why integration changes the economics Historically, each of these layers existed independently: * Fiat access from one vendor * Wallet infrastructure from another * A bridge from a third * Settlement from whichever chain you prefer Every seam adds operational surface area. The Open Money Stack reduces that surface area. With the full OMS, a complete payment flow looks like this: 1. **Funds enter** through regulated fiat rails 2. **They settle** into a smart contract wallet instantly 3. **Orchestration** routes across borders and networks as needed 4. **Polygon finalizes** the transfer in under two seconds 5. **The recipient off-ramps** into local currency through compliant infrastructure Integration does not eliminate flexibility. Institutions can still extend, customize, and interoperate. They can pick and choose what they need. But they are not required to assemble foundational plumbing themselves. **Integrate once. Customize as desired. Move money end-to-end, globally, 24/7.** ## Who it's for * **Payment platforms and fintechs**: replace the patchwork of wallets, ramps, compliance, routing, and settlement vendors with one open stack at better economics * **Fintechs and neobanks**: add stablecoin payment rails with embedded wallets, compliant onramps, and instant settlement in one integration * **Enterprise payments teams**: reduce cross-border costs, unlock 24/7 settlement, and expand globally without assembling per-corridor bank relationships * **Banks and financial institutions**: layer stablecoin settlement onto existing infrastructure without rebuilding core systems * **Enterprises and marketplaces**: automate global payouts with programmable, auditable money flows and pay out counterparties anywhere instantly ## Next steps See how financial institutions are using the Open Money Stack. Pick a use case and follow a guided path into the docs. # Start Building Source: https://docs.polygon.technology/oms/quickstart Choose your path into the Open Money Stack based on what you're building. Pick the starting point that matches your use case. Each path links to the relevant section of these docs. Need regulated rails, custodial infrastructure, compliance services, or a managed chain deployment? [Contact Polygon](https://info.polygon.technology/get-early-access). ## I want to add wallet infrastructure Give users an onchain account with 1-click setup. Social login, passkeys, and smart sessions built into your app. No seed phrases. Integrate an embedded wallet into a React app in minutes. Scoped, time-limited permissions so users approve once and your app handles the rest. Fully managed wallets for regulated products and enterprise deployments. ## I want to add fiat on-/off-ramps Let users move between fiat and crypto without leaving your app. Licensed infrastructure for bank accounts, debit cards, and cash with KYC and AML built in. Buy USDC with a card via Stripe's Crypto Onramp API. Convert onchain stablecoins back to fiat, compliantly. ## I want to accept stablecoin payments Integrate native USDC on Polygon for instant, low-fee settlement. Native USDC integration: instant settlement, low fees, broad wallet support. All stablecoins available on Polygon, with integration guides for USDC and cross-chain transfers. ## I want to enable cross-chain transactions Orchestrate 1-click transactions across any chain, with any token, from any wallet. How Trails handles routing, liquidity aggregation, and gas abstraction across chains. Integrate the Trails Widget, Headless SDK, or Direct API. ## I want to build agentic payment flows Embed payments into AI agents and autonomous applications. CLI toolkit for AI agents: wallets, token operations, x402 micropayments, and onchain identity in a single install. HTTP-native micropayments for pay-per-use APIs and AI agents. ERC-8004 reputation standard and LLM wallet MCP. ## I want to use an existing chain Build on Polygon Chain, the public settlement layer for payments, stablecoins, and enterprise applications. RPC endpoints, chain configuration, and deployment guides for Polygon's public chain. Understand the full blockchain layer: Polygon Chain, Chain Development Kit (CDK), and Agglayer. System requirements, snapshots, and setup guides for running a full node on Polygon Chain. Requirements, staking, and step-by-step setup for running a Polygon validator node. ## I want to deploy my own chain Launch a custom ZK-powered chain with dedicated throughput and compliance controls. Build and launch a ZK-powered chain in days, not months. Cross-chain interoperability and shared liquidity built into every CDK chain by default. # Use Cases Source: https://docs.polygon.technology/oms/use-cases How financial institutions are using the Open Money Stack to move money globally. The Open Money Stack is built for fintechs, payment platforms, and financial institutions that need to move money globally at scale. These are the most common scenarios, each enabled by OMS components that can be adopted independently or together. ## Always-On Account Funding Traditional payment rails run on limited global banking hours. Your users don't. PSPs and neobanks use Polygon's settlement layer to credit accounts and settle merchant balances at any hour, 24/7 globally: evenings, weekends, holidays. Finality in under two seconds. No more queued ACH batches, no settlement lag on Sunday afternoons. Stablecoin rails run continuously, so funding does too. **Who this is for:** PSPs, payment platforms, neobanks, brokerages, and merchant acquirers that need settlement outside banking hours. **OMS components:** Stablecoin Orchestration · Blockchain Rails · Wallet Infrastructure *** ## Cross-Border Business Payments Correspondent banking corridors are slow, opaque, and expensive. Building alternatives from scratch requires bank relationships, licensing, and compliance infrastructure that takes years to assemble. The OMS provides the full stack for cross-border B2B payments: licensed fiat access in sender and receiver currencies, stablecoin settlement on Polygon, and cross-chain routing for corridors that span multiple networks. Platforms can launch global payment products on regulated infrastructure, without starting from zero. **Who this is for:** PSPs, paytechs, payout networks, and fintechs building cross-border B2B payment products, whether serving businesses directly or as a platform layer. **OMS components:** On-/Off-Ramps · Stablecoin Orchestration · Cross-Chain Interop · Blockchain Rails *** ## Dollar Banking for Emerging Markets Consumers and businesses in Latin America, Africa, and Southeast Asia increasingly want USD-denominated accounts: a stable store of value, a better way to send and receive internationally, and protection against local currency volatility. The OMS gives neobanks the building blocks to offer that experience: embedded wallets that look like bank accounts, USDC-backed balances, compliant on- and off-ramp infrastructure, and coverage across 38 countries. Users hold and move dollars without a US bank account; the platform doesn't need one either. **Who this is for:** Stablecoin-first neobanks and consumer fintechs targeting non-US markets. **OMS components:** Wallet Infrastructure · On-/Off-Ramps · Stablecoin Orchestration *** ## Global Payouts at Scale Marketplace platforms, payroll providers, and gig economy companies face the same problem: paying large numbers of workers or sellers in different countries, in different currencies, through different local payment systems. The OMS handles the routing, compliance, and last-mile delivery. Platforms initiate payouts in USDC; the OMS converts and delivers in local fiat across dozens of countries, with KYC, AML, and reporting built into the infrastructure. No per-corridor integrations, no separate compliance stack. **Who this is for:** Marketplaces, payroll platforms, gig economy companies, and PSPs running global payout programs. **OMS components:** On-/Off-Ramps · Stablecoin Orchestration · Blockchain Rails *** ## Stablecoin Payment Acceptance Merchants want the benefits of stablecoin settlement (instant finality, near-zero fees, global reach) without asking customers to manage crypto wallets. Platforms serving merchants want to offer stablecoin acceptance alongside existing payment methods without rebuilding their compliance stack. The OMS provides wallet infrastructure to receive stablecoin payments, automatic conversion to fiat, and compliant offramp delivery to the merchant's bank account. Customers pay in stablecoins; merchants settle in the currency they already use. **Who this is for:** Merchants, merchant payment platforms, and PSPs adding stablecoin acceptance. **OMS components:** Wallet Infrastructure · Stablecoin Orchestration · On-/Off-Ramps *** ## Consumer Remittance Remittance platforms face a structural tension: US regulatory coverage is fragmented by state, last-mile delivery in destination countries requires local banking relationships, and customers expect near-instant transfers at competitive rates. The OMS provides licensed corridor infrastructure with 38-state MTL coverage, stablecoin settlement on Polygon, and offramp delivery in local fiat across international corridors. Platforms can offer debit card, ACH, and cash onramp options without assembling the licensing and bank relationships from scratch. **Who this is for:** Remittance platforms, consumer fintechs serving immigrant populations, and apps with cross-border transfer products. **OMS components:** On/Off Ramps · Stablecoin Orchestration · Blockchain Rails *** ## Embedded Fiat Ramps Crypto wallets, exchanges, and fintech apps need to let users move between fiat and digital assets, but building licensed ramp infrastructure across US states is a multi-year compliance project. The OMS provides white-label and API-based ramp infrastructure with 48-state MTL coverage, support for debit card, ACH, and cash, and both widget and native API integration paths. Platforms embed it; the OMS handles the licensing, KYC, and compliance. **Who this is for:** Crypto wallets, exchanges, and fintech apps embedding USD on/off-ramp experiences for end users. **OMS components:** On-/Off-Ramps · Wallet Infrastructure # ERC-8004 on Polygon Source: https://docs.polygon.technology/payment-services/agentic-payments/agent-integration/erc8004 Reference and explanation for ERC-8004: onchain Identity, Reputation, and Validation registries for autonomous agents. **ERC-8004** defines a lightweight, onchain trust layer for autonomous agents using three registries: **Identity**, **Reputation**, and **Validation**. The standard is designed to work alongside existing agent protocols (A2A, MCP). Payments are out of scope for ERC-8004; however, payment proofs (e.g., from **x402**) can be referenced in reputation data. This page covers what ERC-8004 standardizes, how it relates to A2A, MCP, and x402, and where to find the Polygon mainnet and Amoy deployments. ## Why ERC-8004? Modern agent stacks focus on communication and capability exposure, not on open discovery and trust across organizational boundaries. Google's **A2A** provides agent authentication, capability advertisement via Agent Cards, and orchestration, but does not standardize reputation or validation. Anthropic's **MCP** connects LLM apps to external tools and data, and similarly leaves trust and discovery to individual applications. ERC-8004 adds the missing piece: standard onchain registries that any chain can host as singletons. It links agents to MCP/A2A endpoints through an onchain identity, with optional trust signals. *** ## What ERC-8004 standardizes (at a glance) * **Identity Registry** - an **ERC-721 + URIStorage** registry that mints an *Agent ID* (`agentId`) and points its `tokenURI` to a JSON registration file (e.g., on IPFS/HTTPS) listing A2A/MCP endpoints, DIDs, ENS, wallets, etc. Ownership of the NFT = ownership of the agent entry. * **Reputation Registry** - an interface for clients to submit **feedback** (score `0-100`, optional tags, and an optional off-chain file/URI + hash). Off-chain files may include **payment proofs** to correlate economics with feedback. * **Validation Registry** - a request/response log for **independent validators** (e.g., stake-based re-execution, zkML verifiers, TEEs) to post attestations about an agent's work. Results can be queried onchain. Payments are **orthogonal** to ERC-8004; the spec shows how **x402** proofs can be referenced in reputation data but does not dictate any settlement flow. ## Polygon Deployments ERC-8004 registries are deployed on **Polygon mainnet** and **Polygon Amoy**. ### Polygon Mainnet * **IdentityRegistry:** [0x8004A169FB4a3325136EB29fA0ceB6D2e539a432](https://polygonscan.com/address/0x8004A169FB4a3325136EB29fA0ceB6D2e539a432) * **ReputationRegistry:** [0x8004BAa17C55a88189AE136b182e5fdA19dE9b63](https://polygonscan.com/address/0x8004BAa17C55a88189AE136b182e5fdA19dE9b63) ### Amoy * **IdentityRegistry:** [0x8004ad19E14B9e0654f73353e8a0B600D46C2898](https://amoy.polygonscan.com/address/0x8004ad19E14B9e0654f73353e8a0B600D46C2898) * **ReputationRegistry:** [0x8004B12F4C2B42d00c46479e859C92e39044C930](https://amoy.polygonscan.com/address/0x8004B12F4C2B42d00c46479e859C92e39044C930) * **ValidationRegistry:** [0x8004C11C213ff7BaD36489bcBDF947ba5eee289B](https://amoy.polygonscan.com/address/0x8004C11C213ff7BaD36489bcBDF947ba5eee289B) *** ## Read-Only Examples The snippets below use `viem` to query the Amoy contracts. They are deterministic and read-only, and work before any agents are minted. Note that `tokenURI` and `ownerOf` only resolve for existing `agentId` values. ```ts theme={null} import { createPublicClient, http } from "viem"; import { polygonAmoy } from "viem/chains"; import "dotenv/config"; const IDENTITY = "0x8004ad19E14B9e0654f73353e8a0B600D46C2898" as const; const REPUTATION = "0x8004B12F4C2B42d00c46479e859C92e39044C930" as const; const VALIDATION = "0x8004C11C213ff7BaD36489bcBDF947ba5eee289B" as const; const erc721View = [ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ type:"string" }] }, { type: "function", name: "symbol", stateMutability: "view", inputs: [], outputs: [{ type:"string" }] }, { type: "function", name: "tokenURI", stateMutability: "view", inputs: [{ type:"uint256" }], outputs: [{ type:"string" }] }, ]; const validationView = [ { type:"function", name:"getValidationStatus", stateMutability:"view", inputs:[{type:"bytes32"}], outputs:[{type:"address"},{type:"uint256"},{type:"uint8"},{type:"bytes32"},{type:"uint256"}] }, ]; async function main() { const pub = createPublicClient({ chain: polygonAmoy, transport: http() }); // Identity registry metadata const name = await pub.readContract({ address: IDENTITY, abi: erc721View, functionName: "name" }); const symbol = await pub.readContract({ address: IDENTITY, abi: erc721View, functionName: "symbol" }); console.log({ name, symbol }); // e.g., "Agent Identity", "AGNT" // Sample agentId=1 (will throw if not yet minted) // const uri = await pub.readContract({ address: IDENTITY, abi: erc721View, functionName: "tokenURI", args:[1n] }); // console.log({ uri }); // Check a validation status by requestHash (bytes32) // const reqHash = "0x" + "00".repeat(32) as `0x${string}`; // const status = await pub.readContract({ address: VALIDATION, abi: validationView, functionName: "getValidationStatus", args:[reqHash] }); // console.log({ status }); } main(); ``` ### Where these come from in the spec * Identity uses ERC-721 + URIStorage (hence tokenURI and ownership semantics). * Validation exposes getValidationStatus/getSummary to query results. You can use more [modern interfaces and standards backwards compatible with ERC-721](https://eips.ethereum.org/EIPS/eip-6220) to access the same values if you wish. ### How ERC-8004 Relates to A2A, MCP, and x402 A2A is the coordination layer (authentication, agent cards, lifecycle). ERC-8004 adds discovery and trust so agents from different organizations can find and assess each other. MCP is the tool/data layer. The ERC-8004 Identity record can link to MCP endpoints, allowing agent wallets or marketplaces to enumerate capabilities consistently. x402 is the payment layer. ERC-8004 is payment-agnostic. You can optionally embed payment proofs (such as x402 transaction hashes) in off-chain feedback files referenced by the Reputation registry. ## Design Goals and Current Status ERC-8004 is a Standards Track ERC proposal created August 13, 2025, currently under public review. The standard introduces pluggable trust models (reputation, crypto-economic validation, zk/TEE attestations) with security proportional to the value at risk. The registries are designed to be per-chain singletons for straightforward discovery. Active discussion topics include: handling onchain vs. off-chain data, encouraging multiple independent reputation providers, and keeping payments decoupled while allowing payment proofs to be referenced. Development discussion takes place in the [ERC-8004 Builders](https://t.me/ERC8004) Telegram group and the [Ethereum Magicians forum thread](https://ethereum-magicians.org/t/erc-8004-trustless-agents/25098). # Agentic Payments Introduction Source: https://docs.polygon.technology/payment-services/agentic-payments/agent-integration/intro Conceptual overview of agentic payments and how autonomous agents transact on Polygon. # Agentic Payments Introduction **Agentic Payments** are payments initiated and completed by autonomous software entities (agents) without direct human action at every step. Instead of requiring a person to click "confirm transaction", an agent can negotiate prices, sign intents, and pay onchain in the background, using predefined policies or earned balances. This shifts onchain activity from user-driven to intent-driven. An agent doesn't just send tokens: it executes a purpose, such as subscribing to data, paying per API call, or settling micro-invoices in real time. By encoding payment logic inside agents and standardizing protocols like [x402](https://x402.dev), Polygon allows any intelligent system to become an autonomous economic participant. *** ## What is an Agent? An **agent** is an autonomous program that can perceive, decide, and act on behalf of a user or a system. Agents combine reasoning models (LLMs, decision trees) with access to data, APIs, and onchain actions. They can interpret natural language commands, interact with contracts, and coordinate with other agents without exposing private keys or depending on centralized custody. On Polygon, agents work with a suite of tooling including **AgentKit**, **Model Context Protocol (MCP)**, and **Unified APIs** to perform secure blockchain operations. This ecosystem makes it possible for an AI assistant, a trading bot, or a DAO delegate to act as an onchain entity: context-aware, policy-bounded, and continuously learning. *** ## How Agentic Payments Work Instead of traditional wallet interactions, payments are executed via **intents** or **facilitated flows** such as x402. An agent can detect that an API call costs \$0.002 in USDC, confirm the requirement, and complete the payment automatically, all in milliseconds. Because they are keyless and infrastructure-agnostic, agentic payments work across environments: from local LLMs to decentralized marketplaces. This makes microtransactions, dynamic subscriptions, and per-use pricing viable for both human-facing apps and AI agents. *** ## Standards and Protocols Polygon supports two complementary standards for agentic payments: * **[x402](/payment-services/agentic-payments/x402/intro/)**: An HTTP-based protocol that uses the 402 Payment Required status code to gate API access behind onchain payments. Clients pay per request; no subscription or API key required. * **[ERC-8004](/payment-services/agentic-payments/agent-integration/erc8004/)**: An onchain trust layer for autonomous agents, providing Identity, Reputation, and Validation registries so agents from different organizations can discover and assess each other. # Polygon Agentic CLI Source: https://docs.polygon.technology/payment-services/agentic-payments/polygon-agent-cli A single CLI toolkit for AI agents: smart contract wallets, token operations, x402 micropayments, and onchain identity. The Polygon Agentic CLI is a command-line toolkit that gives AI agents and autonomous applications full access to the Polygon payments stack in a single install. It handles wallet creation, token transfers, cross-chain bridging, x402 micropayments, and ERC-8004 onchain identity without requiring agents to manage multiple SDKs or dependencies. Source code, releases, and contribution guide. ## What it includes | Capability | Description | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | **Smart contract wallets** | Session-based wallets via Sequence. Create and manage wallets with scoped permissions per agent session. | | **Token operations** | Send, swap, bridge, and deposit tokens via Trails routing. Single command for any cross-chain transfer. | | **x402 micropayments** | Pay x402-protected API endpoints and register resources as a seller. Built-in buyer and seller flows. | | **ERC-8004 identity** | Register and update onchain agent identity and reputation. Interact with Identity, Reputation, and Validation registries. | | **Encrypted storage** | AES-256-GCM encrypted local storage for keys and session state. No plaintext secrets on disk. | ## Install ```bash theme={null} npm install -g @0xpolygon/agent-cli ``` Or run directly without installing: ```bash theme={null} npx @0xpolygon/agent-cli ``` ## Quick start **1. Create a wallet** ```bash theme={null} polygon-agent wallet create ``` This generates a smart contract wallet secured by a session key. The private key is stored locally with AES-256-GCM encryption. **2. Fund the wallet** ```bash theme={null} polygon-agent wallet fund --network polygon ``` **3. Send tokens** ```bash theme={null} polygon-agent token send \ --to 0xRecipient \ --amount 10 \ --token USDC \ --network polygon ``` **4. Pay an x402 endpoint** ```bash theme={null} polygon-agent x402 pay --url https://api.example.com/resource ``` The CLI detects the 402 response, constructs the payment, and retries the request automatically. **5. Register agent identity** ```bash theme={null} polygon-agent identity register --name "my-agent" --description "Trading agent" ``` This writes an ERC-8004 identity record on Polygon mainnet. ## Key commands ### Wallet | Command | Description | | ---------------- | ------------------------------------------------ | | `wallet create` | Create a new session-based smart contract wallet | | `wallet list` | List all managed wallets | | `wallet balance` | Show token balances for a wallet | | `wallet export` | Export wallet credentials | ### Token operations | Command | Description | | --------------- | ------------------------------ | | `token send` | Transfer tokens to an address | | `token swap` | Swap tokens via Trails routing | | `token bridge` | Bridge tokens cross-chain | | `token deposit` | Deposit tokens to a protocol | ### x402 | Command | Description | | ------------- | ------------------------------------------------- | | `x402 pay` | Pay an x402-protected endpoint | | `x402 serve` | Protect a local endpoint with x402 payment gating | | `x402 status` | Check payment status for a resource | ### Identity (ERC-8004) | Command | Description | | --------------------- | ------------------------------------------------------------- | | `identity register` | Register onchain agent identity | | `identity update` | Update identity metadata | | `identity reputation` | Read reputation score for an agent address | | `identity verify` | Verify an agent's credentials against the Validation registry | ## Configuration The CLI reads from `~/.polygon-agent/config.json` by default. You can override with `--config`: ```bash theme={null} polygon-agent --config ./my-config.json wallet list ``` Key configuration options: ```json theme={null} { "network": "polygon", "rpc": "https://polygon-rpc.com", "keystore": "~/.polygon-agent/keys", "x402": { "facilitator": "https://facilitator.polygon.technology" } } ``` ## Security * Private keys are encrypted at rest with AES-256-GCM * Session keys are scoped per operation with configurable spending limits * No keys are transmitted to external services ## Related HTTP-native micropayments that the CLI uses under the hood. Onchain identity and reputation standard for agents. MCP server for wallet operations inside Claude and Cursor. Wallet infrastructure designed for autonomous agent use. # Facilitator addresses Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/analytics Reference list of x402 Polygon mainnet and Amoy facilitator addresses for analytics and payment verification. You can also track an up-to-date list of facilitators and their addresses at [facilitators.x402.watch](https://facilitators.x402.watch). ## Polygon Amoy The Amoy testnet facilitator ([x402-amoy.polygon.technology](https://x402-amoy.polygon.technology)) runs **x402 v2**. Signer addresses: ```text theme={null} Address: 0x5a30808427e4C50Abe7430EEA7722CA88379A6a1 Address: 0x7155A302A792C2aD555F2B66E5bC2709044D12dF Address: 0x17070da58e348b27098e1a04e848AC8faA66DA62 Address: 0x812ab2C611D5103a0907028226B756466017FcF8 Address: 0x863f5153F416f0186C762Eeb5Ce7721c694f344e Address: 0x680B2227bde0858A269B4a3FE24eaaFC3C3E1e96 Address: 0x8D7e970Cb3c0865d46C0C5bd3a1c1203a9d12aBc Address: 0x06853A2390c500D351d470d5c191794404AC6FA4 ``` ## Polygon (mainnet) Polygon maintains a rotation of three sets of eight addresses: ``` x402_1.keys:Address: 0x29df60c005506AA325d7179F6e09eB4b4875dAde x402_1.keys:Address: 0xF09A94831C18566781f70937f0996B96EfE691C8 x402_1.keys:Address: 0x42618f623Ec19beFf78dE9DbBFB653BfEaC05D09 x402_1.keys:Address: 0x3202643514D128FF0B4625D2682c0244CF58131c x402_1.keys:Address: 0x11DA3fe5ADA6f5382Ebe972f14C3585DA4E65AeA x402_1.keys:Address: 0x135DfE729F9bbd7F88181E1B708d7506fd499140 x402_1.keys:Address: 0xDcb0Ac359025dC0DB1e22e6d33F404e5c92A1564 x402_1.keys:Address: 0x99EFc08BB42282716fB59D221792f5207f714C9d ``` ``` x402_2.keys:Address: 0xbE5115800247405f020197BF473eBFd085a2C635 x402_2.keys:Address: 0x5eAb3D78264Dab340340d6a37Ff0836464Ae5773 x402_2.keys:Address: 0xE5D4197eFd5D03E3f30cBf11C0fF63Eb95a0A656 x402_2.keys:Address: 0xfac8Edb989f1ba7F9dBb7A1233542D4e1fD6144F x402_2.keys:Address: 0xaFdbfaCb5ed691bf0bCFA660901f299ce9775489 x402_2.keys:Address: 0x1e48Ed59a502D0B324CdAf83362865b3ff49ABa2 x402_2.keys:Address: 0xA1dcBDC2C34577ACD4A1152A98807B2f281A112e x402_2.keys:Address: 0x9e281D4e26E1a4e7C27014E2ca8Cee7F2D44fa52 ``` ``` x402_3.keys:Address: 0x76FCb8ae3365A487E6EA235386C1cf3AbADeDA60 x402_3.keys:Address: 0x9523B120C75640469f1D16490Da0388928229452 x402_3.keys:Address: 0x153F3A70e4400c211d9B482b62aD721Bb02F96F6 x402_3.keys:Address: 0xd5dD012019C58882Dd507A8b3fCBB7b62e9a24c3 x402_3.keys:Address: 0xfff23108338C218F895d75980E14688218D4E92a x402_3.keys:Address: 0xF744e153Ef63f7EEe4a58e0F13761D16C2125EE3 x402_3.keys:Address: 0x0a8B10FE8Bd3072351600Adef4796F3F7aF72Ab0 x402_3.keys:Address: 0x971b4079A618F72Fa0F1792b07ed5923dfBF3500 ``` ## ThirdWeb ``` 0x80c08de1a05Df2bD633CF520754e40fdE3C794d3 ``` ## Questflow ``` 0x4a288FA07fC40F701e4fd2620F0a14338e12a4D7 ``` ## PayAI ``` 0xc6699d2aadA6c36Dfea5C248DD70f9CB0235cB63 ``` ## x402.rs ``` 0xD8Dfc729cBd05381647EB5540D756f4f8Ad63eec ``` ## Corbits ``` 0x06F0BfD2C8f36674DF5cdE852c1eeD8025C268C9 ``` # x402 Directory Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/directory Directory of x402-gated APIs that settle on Polygon. This page lists x402 APIs that settle on Polygon. To add your API, contact the Polygon team. Directory listing is available in the full docs. # x402 How It Works Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/guides/how-it-works Conceptual explanation of the x402 protocol: components, payment flow, design goals, and known limitations. The x402 protocol lets clients pay for HTTP resources (APIs, endpoints, content) via blockchain transactions (with [fiat support in progress](https://github.com/coinbase/x402/pull/446)). A server responds with HTTP 402 ("Payment Required"), the client pays, and the server grants access. No subscription, API key, or manual onboarding is required. *** ## 1. Components | Component | Role | Example / note | | ------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Client** | Requests a resource & pays | Browser, AI agent, mobile SDK | | **Resource Server** | Protects endpoint, issues-402, verifies payment | API or web service | | **Facilitator** | Optional verification + settlement layer | Offloads blockchain logic [oai\_citation:1‡QuickNode](https://www.quicknode.com/guides/infrastructure/how-to-use-x402-payment-required?utm_source=chatgpt.com) | | **Payment Scheme** | Defines chain, token, network, and format | e.g., USDC on Polygon, ERC-3009 scheme | *** ## 2. Payment Flow Sequence The typical sequence for one request: 1. Client → Resource Server: **HTTP GET /endpoint** 2. Resource Server → Client: **HTTP 402 Payment Required**, body includes `PaymentRequirements` describing required payment. 3. Client selects a requirement, builds a `PaymentPayload`, encodes it (e.g., Base64) in header `X-PAYMENT` and retries request. 4. Resource Server verifies the payload (either locally or via the Facilitator). 5. Facilitator / Resource Server settles payment onchain (if not already). 6. Resource Server → Client: **HTTP 200 OK**, body includes the requested resource, header `X-PAYMENT-RESPONSE` contains receipt details. Steps 2-3 can be skipped if the client already knows the payment requirement ahead of time. *** ## 3. Implementation Snapshot ### Server (Seller Side) * Protect endpoint with middleware (e.g.,\ `paymentMiddleware("0xYourAddress", { "/path": { price:"$0.01", network:"polygon" } })`). * On first unauthorized request: respond `402` with JSON: ```json theme={null} { "x402Version": 1, "accepts": [ { "scheme": "erc-3009", "network": "polygon", "token": "USDC_address", "maxAmountRequired": "1000000", // atomic units "description": "Access to premium API" } ], "error": null } ``` ```` On retry with X-PAYMENT header: verify using facilitator or your logic, then return 200 OK and include: ```http X-PAYMENT-RESPONSE: ```` Full tutorial: [x402 Quickstart for Sellers](./quickstart-sellers.mdx) ### Client (Buyer Side) * Send initial request → get 402 + payment info. * Build payment per the scheme (client signs, selects token/chain). * Retry request adding header: ```http theme={null} X-PAYMENT: ``` * Receive 200 OK and decode header X-PAYMENT-RESPONSE to confirm payment details. Full tutorial: [x402 Quickstart for Buyers](./quickstart-buyers.mdx) ### Facilitator (optional) Provides endpoints such as `/verify` and `/settle` for payment payloads. ```http theme={null} POST /verify { "x402Version":1, "paymentHeader": "", "paymentRequirements": { … } } ``` Facilitators can implement their own logic to verify the payment payload and settle the payment onchain, and they can also choose how and when to settle - some will compile queues of settlements to do later, while others will settle instantly. ## Key Design Goals and Benefits * **HTTP-native**: Uses standard HTTP codes and headers. No additional protocol layer. * **Chain and token agnostic**: Works across any chain or stablecoin (e.g., USDC). * **Minimal integration**: One-line middleware on the server side, or a few client calls on the buyer side. * **Micropayments**: Low friction and low cost, suitable for per-request pricing. * **Autonomous agents**: AI systems can transact without per-transaction human approval. ## Known Limitations and Future Directions * Use the correct network label (e.g., `"polygon-amoy"` vs. `"polygon"`). Mismatches cause payment failures. * The protocol is still evolving. Some paid endpoints may require settlement delays. * For high-volume usage, consider deferred payment flows: aggregate many calls, then settle in batch. * Protocol governance is managed by an open community to prevent vendor lock-in. # x402 Quickstart for Buyers Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/guides/quickstart-buyers Tutorial: set up an x402 buyer client on Polygon to automatically pay for and access paywalled API endpoints. This tutorial walks through setting up an x402 buyer client on Polygon. By the end, your client will automatically detect 402 Payment Required responses, pay in USDC, and retrieve the unlocked resource. This tutorial uses test credentials and local endpoints for clarity. In production, never expose private keys or facilitator URLs publicly. ## Prerequisites | Requirement | Example / Notes | | --------------- | -------------------------------------------------------------------------------- | | Wallet | Metamask, Rabby, or any Polygon-compatible wallet with USDC | | JS env | Node.js 18+ with npm or something of better quality, like [Bun](https://bun.sh/) | | Polygon testnet | Amoy RPC | | .env | Must include PRIVATE\_KEY, .KEY; optional FACILITATOR\_URL, RESOURCE\_URL | ## Install dependencies Install one of the official HTTP clients: > Wherever `bun` is used, replace it with `npm` or your preferred package manager. ```bash theme={null} bun install x402-fetch # or bun install x402-axios ``` We will use x402-fetch in this tutorial. Then install viem + dotenv: ```bash theme={null} bun install viem dotenv ``` ## Create a wallet client Set up a Polygon wallet using [viem](https://viem.sh/). This wallet signs and sends the USDC payment when a 402 challenge is detected. ```ts theme={null} import { createWalletClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { polygonAmoy } from "viem/chains"; import "dotenv/config"; const privateKey = process.env.PRIVATE_KEY; if (!privateKey) throw new Error("PRIVATE_KEY not set in .env"); const account = privateKeyToAccount(`0x${privateKey}`); const client = createWalletClient({ account, chain: polygonAmoy, transport: http(), }); console.log("Wallet address:", account.address); ``` Expected output: ```bash theme={null} Wallet address: 0x1234abcd... ``` ## Make paid requests automatically Use x402-fetch or x402-axios to intercept 402 responses and complete the payment automatically. ```ts theme={null} import { wrapFetchWithPayment, decodeXPaymentResponse } from "x402-fetch"; import { createWalletClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { polygonAmoy } from "viem/chains"; import "dotenv/config"; const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`); const client = createWalletClient({ account, chain: polygonAmoy, transport: http() }); const fetchWithPayment = wrapFetchWithPayment(fetch, client); const FACILITATOR_URL = process.env.FACILITATOR_URL || "https://x402-amoy.polygon.technology"; const RESOURCE_URL = process.env.RESOURCE_URL || "http://127.0.0.1:4021/weather"; (async () => { const response = await fetchWithPayment(RESOURCE_URL, { method: "GET" }); const body = await response.json(); console.log("Response body:", body); if (body.report) { const rawPaymentResponse = response.headers.get("x-payment-response"); console.log("Raw payment header:", rawPaymentResponse); const decoded = decodeXPaymentResponse(rawPaymentResponse); console.log("Decoded payment:", decoded); } })(); ``` The client: * Sends the request * Receives 402 Payment Required * Pays in USDC via facilitator * Retries automatically * Returns the unlocked JSON data ## Reference Configuration, error codes, and guardrails. ### Schema | name | type | required | example | description | | ---------------- | ------ | -------- | ----------------------------------------- | ---------------------- | | PRIVATE\_KEY | string | ✅ | `"abcd1..."` | Wallet key for Polygon | | FACILITATOR\_URL | string | optional | `"https://x402-amoy.polygon.technology"` | Payment relay endpoint | | RESOURCE\_URL | string | ✅ | `"https://api.example.com/paid-endpoint"` | Target API URL | | USDC | token | implied | USDC on Polygon | Payment asset | ### Errors Common failure modes and fixes: | code / case | meaning | fix | | -------------------- | --------------------------- | ------------------------------------------- | | MISSING\_CONFIG | Wallet or URL not set | Verify .env keys | | DUPLICATE\_PAYMENT | Payment replay detected | Retry with new request ID | | BAD\_PAYMENT\_HEADER | Invalid signature or amount | Ensure client and facilitator are in sync | | 402\_LOOP | API keeps returning 402 | Check facilitator health or endpoint config | ### Do / Don't Do Guardrails | ✅ Do | ❌ Don't | | ---------------------------------------- | ------------------------------------- | | Use a sandbox facilitator for testing | Hardcode private keys in your scripts | | Log decoded payment responses | Parse payment headers manually | | Use `wrapFetchWithPayment` or x402-axios | Re-implement 402 logic yourself | ### References * [x402-fetch npm docs](https://www.npmjs.com/package/x402-fetch) * [x402-axios npm docs](https://www.npmjs.com/package/x402-axios) * [x402 Developer Docs](https://x402.dev) # x402 Quickstart for Sellers Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/guides/quickstart-sellers Tutorial: protect API endpoints with x402 payment middleware to accept USDC payments on Polygon. This tutorial shows how to add x402 payment middleware to your API or service. By the end, buyers and AI agents will automatically pay in USDC when accessing your protected endpoints. These snippets are for demonstration only. Store private keys and facilitator URLs in a secure vault. Never hardcode secrets. ## Prerequisites | Requirement | Example / Notes | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | | Wallet to receive USDC | Any EVM-compatible wallet (Metamask, Rabby, Safe, etc.) | | JS end | [Node.js ≥18](https://nodejs.org/en) with npm, or something of better quality, like [Bun](https://bun.sh/) | | Existing API / server | Express, Next.js, Hono, or any web framework | | Polygon network | [Amoy testnet](https://wiki.polygon.technology/docs/pos/polygon-bridge/amoy-bridge-guide/) or mainnet | ## Install dependencies > Wherever `bun` is used, replace it with `npm` or your preferred package manager. Pick your middleware: ```bash theme={null} bun install x402-express ``` or ```bash theme={null} bun install x402-next ``` or ```bash theme={null} bun install x402-hono ``` ## Configure the payment middleware Each middleware protects your API routes and routes payments to your receiving wallet. You must specify: * Wallet address: where you receive USDC * Network: e.g. "polygon-amoy" or "polygon" * Facilitator URL: default for Polygon is [https://x402.polygon.technology](https://x402.polygon.technology) * Route config: endpoint price and optional metadata ### Example - Express ```ts theme={null} import express from "express"; import { paymentMiddleware } from "x402-express"; const app = express(); app.use(paymentMiddleware( "0xCA3953e536bDA86D1F152eEfA8aC7b0C82b6eC00", // receiver wallet { "GET /weather": { price: "$0.001", network: "polygon", config: { description: "Get current weather data for any location", inputSchema: { type: "object", properties: { location: { type: "string" } } }, outputSchema: { type: "object", properties: { weather: { type: "string" }, temperature: { type: "number" } } } } } }, { url: process.env.FACILITATOR_URL || "https://x402.polygon.technology" } )); app.get("/weather", (req, res) => { res.send({ report: { weather: "sunny", temperature: 70 } }); }); app.listen(4021, () => { console.log("Server running at http://localhost:4021"); }); ``` Buyers calling `/weather` will automatically receive a 402 challenge, pay, and then receive the weather data. ### Example - Next.js ```ts theme={null} import { paymentMiddleware } from "x402-next"; export const middleware = paymentMiddleware( "0xYourAddress", // receiving wallet { "/protected": { price: "$0.01", network: "polygon-amoy", config: { description: "Access to protected content" } } }, { url: "https://x402.polygon.technology" } ); export const config = { matcher: ["/protected/:path*"] }; ``` Buyers calling `/protected` will automatically receive a 402 challenge, pay, and then receive the protected content. ### Example - Hono ```ts theme={null} import { paymentMiddleware } from "x402-next"; export const middleware = paymentMiddleware( "0xYourAddress", // receiving wallet { "/protected": { price: "$0.01", network: "polygon-amoy", config: { description: "Access to protected content" } } }, { url: "https://x402.polygon.technology" } ); export const config = { matcher: ["/protected/:path*"] }; ``` Buyers calling `/protected` will automatically receive a 402 challenge, pay, and then receive the protected content. ## Reference Configuration parameters, error codes, and guardrails. ### Schema | name | type | required | example | description | | ---------------- | ------ | -------- | ----------------------------------- | --------------------------------------- | | walletAddress | string | ✅ | `0xYourAddress` | Address that receives USDC payments | | network | string | ✅ | `polygon`. | Network Identifier | | price | string | ✅ | `"$0.001"` | Cost per request in USDC | | FACILITATOR\_URL | string | optional | `"https://x402.polygon.technology"` | Payment facilitator endpoint | | config | object | optional | JSON schema | Used for discoverability in x402 Bazaar | ### Do / Don't Do Guardrails | ✅ Do | ❌ Don't | | ------------------------------------------------- | ------------------------------------------------------ | | Use `https://x402.polygon.technology` for Polygon | Expose private keys in middleware | | Include schema metadata for AI discoverability | Hardcode facilitator URLs in code | | Test with Amoy before mainnet deployment | Skip setting network/price, as buyers will fail to pay | ### References * [x402-express npm docs](https://www.npmjs.com/package/x402-express) * [x402-next npm docs](https://www.npmjs.com/package/x402-next) * [x402-hono npm docs](https://www.npmjs.com/package/x402-hono) * [x402 Developer Docs](https://x402.dev) * [Coinbase x402 examples](https://github.com/coinbase/x402/tree/main/examples/typescript/servers) * [Polygon quickstart repo](https://github.com/AkshatGada/x402_Polygon/tree/feature/facilitator-amoy/demo/quickstart-local) ### Errors | case / code | meaning | fix | | ---------------- | ---------------------------- | ---------------------------------- | | 402\_LOOP | Client can't fulfill payment | Check facilitator URL and wallet | | INVALID\_NETWORK | Wrong network label | Use "polygon-amoy" or "polygon" | | BAD\_CONFIG | Missing route schema | Define price and network per route | # Using the Polygon Facilitator Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/guides/using-polygon-facilitator Reference for the Polygon x402 facilitator: endpoint URLs and signing addresses. ## Polygon mainnet The Polygon mainnet facilitator is available at [x402.polygon.technology](https://x402.polygon.technology). Health status is available at [https://x402.polygon.technology/health](https://x402.polygon.technology/health). To add the Polygon Facilitator to your API, follow the [x402 Quickstart for Sellers](./quickstart-sellers.mdx). To use it as part of a multi-facilitator setup, see [Using the x402facilitators package](/payment-services/agentic-payments/x402/guides/using-x402facilitators/). ### Mainnet signer addresses Polygon maintains a rotation of three sets of eight addresses: ```text theme={null} x402_1.keys:Address: 0x29df60c005506AA325d7179F6e09eB4b4875dAde x402_1.keys:Address: 0xF09A94831C18566781f70937f0996B96EfE691C8 x402_1.keys:Address: 0x42618f623Ec19beFf78dE9DbBFB653BfEaC05D09 x402_1.keys:Address: 0x3202643514D128FF0B4625D2682c0244CF58131c x402_1.keys:Address: 0x11DA3fe5ADA6f5382Ebe972f14C3585DA4E65AeA x402_1.keys:Address: 0x135DfE729F9bbd7F88181E1B708d7506fd499140 x402_1.keys:Address: 0xDcb0Ac359025dC0DB1e22e6d33F404e5c92A1564 x402_1.keys:Address: 0x99EFc08BB42282716fB59D221792f5207f714C9d ``` ```text theme={null} x402_2.keys:Address: 0xbE5115800247405f020197BF473eBFd085a2C635 x402_2.keys:Address: 0x5eAb3D78264Dab340340d6a37Ff0836464Ae5773 x402_2.keys:Address: 0xE5D4197eFd5D03E3f30cBf11C0fF63Eb95a0A656 x402_2.keys:Address: 0xfac8Edb989f1ba7F9dBb7A1233542D4e1fD6144F x402_2.keys:Address: 0xaFdbfaCb5ed691bf0bCFA660901f299ce9775489 x402_2.keys:Address: 0x1e48Ed59a502D0B324CdAf83362865b3ff49ABa2 x402_2.keys:Address: 0xA1dcBDC2C34577ACD4A1152A98807B2f281A112e x402_2.keys:Address: 0x9e281D4e26E1a4e7C27014E2ca8Cee7F2D44fa52 ``` ```text theme={null} x402_3.keys:Address: 0x76FCb8ae3365A487E6EA235386C1cf3AbADeDA60 x402_3.keys:Address: 0x9523B120C75640469f1D16490Da0388928229452 x402_3.keys:Address: 0x153F3A70e4400c211d9B482b62aD721Bb02F96F6 x402_3.keys:Address: 0xd5dD012019C58882Dd507A8b3fCBB7b62e9a24c3 x402_3.keys:Address: 0xfff23108338C218F895d75980E14688218D4E92a x402_3.keys:Address: 0xF744e153Ef63f7EEe4a58e0F13761D16C2125EE3 x402_3.keys:Address: 0x0a8B10FE8Bd3072351600Adef4796F3F7aF72Ab0 x402_3.keys:Address: 0x971b4079A618F72Fa0F1792b07ed5923dfBF3500 ``` ## Polygon Amoy The Polygon Amoy testnet facilitator is available at [x402-amoy.polygon.technology](https://x402-amoy.polygon.technology). Health status is available at [https://x402-amoy.polygon.technology/health](https://x402-amoy.polygon.technology/health). **The Amoy facilitator runs x402 v2.** Use a v2-compatible client when targeting this endpoint (see the [x402 Quickstart for Buyers](./quickstart-buyers.mdx) for Amoy examples). ### Amoy signer addresses ```text theme={null} Address: 0x5a30808427e4C50Abe7430EEA7722CA88379A6a1 Address: 0x7155A302A792C2aD555F2B66E5bC2709044D12dF Address: 0x17070da58e348b27098e1a04e848AC8faA66DA62 Address: 0x812ab2C611D5103a0907028226B756466017FcF8 Address: 0x863f5153F416f0186C762Eeb5Ce7721c694f344e Address: 0x680B2227bde0858A269B4a3FE24eaaFC3C3E1e96 Address: 0x8D7e970Cb3c0865d46C0C5bd3a1c1203a9d12aBc Address: 0x06853A2390c500D351d470d5c191794404AC6FA4 ``` # Using x402facilitators package Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/guides/using-x402facilitators How to use the @swader/x402facilitators package to add multi-facilitator routing to x402 middleware. `@swader/x402facilitators` bundles every public x402 facilitator (Polygon, Coinbase, Kamiyo, Questflow, and others) into a single package so your middleware can swap or load-balance providers with minimal code. * Import `auto` for automatic routing across healthy facilitators. * Import named facilitators (e.g., `polygon`, `coinbase`, `thirdweb`) for explicit routing or when you need to supply custom credentials. * Use discovery helpers to enumerate every resource a facilitator can serve, useful for LLM agents that need to list tools before calling them. The package is pure TypeScript and mirrors the data shown on [facilitators.x402.watch](https://facilitators.x402.watch). ## When to Use This Package * You are a seller and want your API to accept requests from multiple facilitators without hardcoding URLs. * You are a buyer or agent who needs the same code to work on Polygon Amoy today and on Base or Solana in the future. * You maintain an orchestrator or LLM agent registry and need to query facilitator metadata and discovery endpoints programmatically. * You have already completed the [x402 Quickstart for Buyers](./quickstart-buyers.mdx) or Sellers and now need production-ready facilitator management. ## Install ```bash theme={null} bun add @swader/x402facilitators # npm install @swader/x402facilitators ``` > Tip for LLM agents: store the package name as `x402facilitators` and check > `package.json` before reinstalling. ## Multi-Facilitator Routing ```ts theme={null} import { paymentMiddleware } from "x402"; // pseudocode - use your client import { auto } from "@swader/x402facilitators"; paymentMiddleware(address, resources, auto); ``` * `auto` distributes requests across healthy facilitators, keeping your service online if one provider has downtime. * Agents can use this by routing all payment middleware through `auto` without any additional configuration. ## Choose Explicit Facilitators ```ts theme={null} import { coinbase, questflow, polygon, thirdweb, } from "@swader/x402facilitators"; paymentMiddleware(address, resources, polygon); paymentMiddleware(address, resources, coinbase({ apiKey: process.env.CDP_API_KEY!, })); paymentMiddleware(address, resources, thirdweb({ secretKey: process.env.THIRDWEB_SECRET_KEY!, })); ``` * Each facilitator exports both the config function and a metadata object (e.g., `coinbaseFacilitator`) for use in dashboards. * Simple facilitators (`polygon`, `payai`, `x402rs`, etc.) return a plain `{ url }` config and require no additional props. ## Discover Facilitator Resources Programmatically ```ts theme={null} import { discoverableFacilitators, listAllFacilitatorResources, kamiyoDiscovery, } from "@swader/x402facilitators"; const kamiyoResources = await listAllFacilitatorResources(kamiyoDiscovery); const everything = await Promise.all( discoverableFacilitators.map(listAllFacilitatorResources) ); console.log(everything.flat()); ``` * Call this before planning an autonomous workflow to enumerate every tool guarded by Kamiyo, Coinbase, Questflow, and others. * Cache the results. Discovery endpoints may rate-limit anonymous callers. ## Next Steps * To use the Polygon-hosted facilitator directly, see [Using the Polygon Facilitator](./using-polygon-facilitator.mdx). * If you have not yet wired up payments, start with the [x402 Quickstart for Buyers](./quickstart-buyers.mdx), then add `@swader/x402facilitators` on top. * To contribute a new facilitator: fork the upstream repo, add `src/facilitators/.ts`, export it from `src/lists/all.ts`, and run `bun run build`. The PR will publish to npm and appear on [facilitators.x402.watch](https://facilitators.x402.watch). Reference: [`Swader/x402facilitators`](https://github.com/Swader/x402facilitators/). # x402 Introduction Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/intro What x402 is and how Polygon supports it: available networks, facilitators, and where to start. x402 is an open payment protocol that brings blockchain payments into the HTTP standard. By reusing the HTTP 402 Payment Required status code, it lets developers handle onchain and agentic payments with the same tools they already use for APIs and web services. Instead of building complex wallet integrations or subscription systems, developers can treat payments like any other part of the HTTP request/response cycle. This approach works for web2 developers experimenting with paid APIs and for web3 builders who need a lightweight way to support pay-per-use APIs, agent-to-agent transactions, and micropayments. [Read more about x402 here](https://x402.gitbook.io/x402). ## Access on Polygon Polygon supports x402 on Mainnet and Amoy through the following facilitators: 1. Polygon Mainnet Facilitator: [https://x402.polygon.technology](https://x402.polygon.technology) 2. Polygon Testnet Facilitator: [https://x402-amoy.polygon.technology](https://x402-amoy.polygon.technology) 3. [ThirdWeb](https://playground.thirdweb.com/payments/x402) 4. [x402.rs Facilitator Endpoint](https://facilitator.x402.rs/) 5. [Pay.AI](https://payai.network/) 6. [Corbits](https://docs.corbits.dev/about-x402/facilitators) 7. [Questflow](https://facilitator.questflow.ai/) To implement x402 with Polygon and your applications or agents, follow the tutorials and guides in these docs. Alternatively, the x402 community has created [multiple examples](https://github.com/coinbase/x402/tree/main/examples/typescript) which can be adapted for Polygon. # x402 Autopay Source: https://docs.polygon.technology/payment-services/agentic-payments/x402/tools/autopay How to install and use the AutoPay Chromium extension for x402 micropayments in the browser. AutoPay is a Chromium extension that lets you fund a wallet for browser-based micropayments and automatically pays for any x402 API endpoint it encounters. While x402 is primarily designed for agent-to-agent payments, AutoPay extends that model to human users browsing the web. A basic demo video of how it works is here: