# About Aligned

### What is Aligned?

Aligned is a vertically integrated stack for building applications on a verifiable internet. Whether it's financial infrastructure or AI systems, we provide the foundation for provable execution with one-click solutions for wallets, rollups, interoperability, and ZK services in a world where trust is no longer a given.

### Mission

Aligned is creating the foundation for a trustless, verifiable internet. Our vertically integrated stack empowers developers to build applications across finance, AI, and other sectors with one-click solutions for wallets, rollups, and zero-knowledge services on Ethereum. We’re focused on enabling provable execution in a world where institutional trust is increasingly fragile.

By providing the tools for trust to be integrated into every layer of application infrastructure, we’re enabling developers to create verifiable systems that can be trusted across a wide range of use cases. Aligned is here to enable a future where trust is not assumed, but proven by design.

{% hint style="info" %}
If you are unfamiliar with ZK and why this is useful, see [Why ZK and Aligned?](/introduction/4_why_zk)
{% endhint %}

### What real value does Aligned bring to the table?

Aligned is building a full stack of vertically integrated infrastructure designed to make it easier for teams to launch, operate, and scale on Ethereum.

Aligned suite of products and services includes:

* ZK Verification Layer (offering Proof Verification Layer and Proof Aggregation Service)
* Rollup-as-a-Service (RaaS) Platform
* Meta-Proving Services
* Interoperability Protocol
* Wallet-as-a-Service

![Figure 1: Aligned Suite of Products](/files/8qivgZFSqE1fhzKcNB9l)

Read more: [The Aligned Roadmap](https://roadmap.alignedlayer.com)

By vertically integrating our stack we can provide the best developer experience and highest performance at the lowest possible cost.

* Fully open-source—no proprietary code or licenses
* Simplicity and minimalism—easy to maintain
* Modular and flexible—customizable to meet your business needs
* Future-proofed—designed to support emerging technologies

Whether you’re a seasoned crypto builder or an enterprise launching your first blockchain project, Aligned gives you the tools to deploy powerful Ethereum-native infrastructure without compromising on security, performance, or flexibility.

As Ethereum continues to be adopted as the financial backend of the internet, we are committed to helping developers and companies tap into its security and global, 24/7 liquidity.

### What limits the development of more complex applications on top of blockchains?

The main limitation for building complex applications on top of blockchains has been that the computation can run only a few milliseconds on-chain, and even then, this can be costly. You can't have millions of daily active users using Ethereum or any blockchain at the same time.

ZK solves this, but due to slow and complex-to-use proving and expensive verification, progress has been limited. In the case of proving, before the development of general-purpose zero-knowledge virtual machines (zkVMs), users had to express their computation as arithmetic circuits, making the developer experience something like coding in assembler, error-prone, and complex. Moreover, proof systems depended on trusted setups, adding additional trust guarantees, the need to carry out special ceremonies to initialize parameters, and delaying go-to-market times. Besides, having high verification costs (on the order of 10's to 100's of dollars per proof) meant that only those projects with a huge capital could afford to build such applications.

### How much can Aligned Aligned’s ZK Verification Layer reduce costs?

Aligned’s ZK Verification Layer operates using two operation modes: Proof Verification Layer and Proof Aggregation Service. The cost reduction depends on throughput, proof system, and mode used. For the least expensive systems, such as Groth16, this can amount to nearly 90%, while STARKs can be nearly 99%. Moreover, Aligned’s stack allows the verification of proofs that cannot be currently verified in Ethereum due to cost or size, such as Kimchi or Binius. The verification cost using Aligned services is independent of the proof system, giving the choice of the proof system back to developers.

### How does Aligned’s stack compare to other solutions?

Aligned has created a new category in crypto: ZK verification layer. It is the only solution for now offering Proof Verification and Proof Aggregation modes while being linked to Ethereum via EigenLayer. The Proof Verification Layer provides very high throughput (over two orders of magnitude more than Ethereum), low latency, and lower costs than the Proof Aggregation Layer. The security is provided by restaking, and this mode is well suited for applications with tight limits on latency and costs. The Proof Aggregation Layer works using the slower proof recursion strategy, also used in rollups to compress proofs. Another key feature is that Aligned’s approach is stateless, simplifying the process greatly.

Other solutions focus on building a separate L1 for proof verification (which sets them apart from Ethereum and requires bootstrapping the economic security, which can be lowered and subject to volatility, as opposed to that provided by restaking) or focus on the aggregation of proofs from a few proof systems. This last approach adds latency, higher operational costs, and constrains the developer's choice of the proof system.

The following table contains cost estimates for Aligned, assuming a batch size of 20 proofs.

| Proof system | Ethereum   | Aligned's Proof Verification Layer | Aligned's Proof Aggregation Service |
| ------------ | ---------- | ---------------------------------- | ----------------------------------- |
| Groth16      | 250,000    | 40,000                             | TBD                                 |
| STARKs       | >1,000,000 | 40,000                             | TBD                                 |
| Kimchi-IPA   | ??????     | 40,000                             | TBD                                 |
| Binius.      | ??????     | 40,000                             | TBD                                 |

### Why is Aligned building its stack?

Aligned is building its stack to provide the foundational infrastructure for a trustless, verifiable internet. Aligned’s vertically integrated stack empowers developers to build applications across industries like finance and AI, offering one-click solutions for rollups, wallets, and several zero-knowledge (ZK) services.

In recent months, we have witnessed the development and enhancement of general proving virtual machines such as Risc0, Valida, Jolt, and SP1. These innovations allow users to write ordinary code in languages like Rust or C and generate proofs demonstrating the integrity of computations. This evolution is poised to transform application development, provided we have verification networks with high throughput and low cost. This is the core vision of Aligned and the reason we are building it: the future belongs to provable applications.

Currently, proof verification in Ethereum is expensive and throughput is limited to around 10 proofs per second. The cost depends on the proof system used, and the availability of precompiles. Groth16 costs around 250,000 gas, STARKs, over 1,000,000, and other proof systems are too expensive to be used in Ethereum.

Proof technology has been evolving over the last decade, with new arguments, fields, commitments and other tools appearing every day. It is hard to try new ideas if verification costs are high, and there is a considerable go-to-market time, as a consequence of development time of new, gas-optimized smart contracts, or the inclusion of new precompiles to make them affordable.

Aligned’s stack provides an alternative to reduce costs and increase throughput significantly. This is achieved by two different products: Proof Verification Layer and Proof Aggregation Service.

The Proof Verification Layer works with a subset of Ethereum’s validators via restaking. Validators (also known as Operators) receive proofs, verify them using the verification code written in Rust or any other higher-level language, and then sign messages with BLS signatures. If a two-thirds (2/3) majority agrees, the results are posted in Ethereum.

Since Aligned’s operators only need to run the verification code on bare metal, we have several advantages compared to running it on top of the EVM:

* The code can be optimized for speed, not gas consumption.
* We can leverage parallelization to increase throughput.
* Since the gas limit does not constrain us, we can verify proof systems that are too expensive for Ethereum, such as Kimchi or Binius.
* Adding new proof systems is straightforward.

Preliminary numbers show that Aligned’s Verification Layer can verify more than 1000 proofs per second, over two orders of magnitude more than the EVM at nominal capacity. Using effective batching techniques, we can split the task creation and verification cost between thousands of proofs.

On the other hand, Aligned’s Proof Aggregation service enables cost-efficient ZK proof verification by combining multiple proofs into one using recursive proof aggregation. It can be used standalone or with our Proof Verification Layer. Ideal for services like rollups that require Ethereum’s full security but can tolerate higher latency.

To complement these verification capabilities, Aligned’s Meta-proving Services offers an easy interface for accessing centralized and decentralized proving from external providers. Many developers building programs on Aligned with zkVMs will want to delegate proving to different service providers. To address this, we will have a simple SDK that allows developers to code in Rust and easily send their programs for proving to their preferred services.

Aligned’s stack also provides a one-click solution for wallets and rollups. With Aligned’s Wallet-as-a-service infrastructure, developers can easily generate embedded wallets for users, supporting rollups and mobile integrations. It will leverage the latest account abstraction technology, offering seamless wallet services backed by our robust tech stack. And rollups Aligned's RaaS platform simplifies ZK-rollup deployment, allowing clients to launch L2 chains without needing deep blockchain expertise. It streamlines the process for developers and is also adding support for based rollups, a crucial element of Ethereum’s roadmap.

As a key component of Aligned’s vision, Aligned’s Interoperability Protocol will offer an intent-based bridge that will be integrated with our RaaS stack. It will leverage based sequencing and enable developers to create native trust-minimized solutions for users and financial institutions to efficiently move liquidity across chains. With each of these products, we are taking concrete steps toward fulfilling our mission of building a trustless and verifiable internet. By providing developers with the tools to create scalable, efficient, and secure applications, Aligned is tackling the fundamental challenges of trust that have long hindered the potential of blockchain and decentralized technologies.

### Future additions

* Propagation of the results to different L2s


# Try Aligned

In this tutorial, you will learn how to send your first SP1 proofs to get verified in Aligned in under 3 minutes.

{% hint style="warning" %}
This tutorial is for sending proofs on Hoodi network. To send proofs on Mainnet, please refer to the [submitting proofs](/guides/0_submitting_proofs) guide.
{% endhint %}

## Quickstart

We will download a previously generated SP1 proof, send it to Aligned for verification, and retrieve the results from Ethereum Hoodi testnet.

1. Download and install Aligned to send proofs in the testnet:

```bash
curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/crates/cli/install_aligned.sh | bash
```

2. Run the `source` command that should appear in the shell
3. Download the example SP1 proof file together with the ELF file of the proved program using:

```bash
curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/crates/cli/get_proof_test_files.sh | bash
```

4. Send the proof to be verified in Aligned with

```bash
rm -rf ~/.aligned/aligned_verification_data/ &&
aligned submit \
--proving_system SP1 \
--proof ~/.aligned/test_files/sp1_fibonacci_5_0_0.proof \
--vm_program ~/.aligned/test_files/sp1_fibonacci_5_0_0.elf \
--public_input ~/.aligned/test_files/sp1_fibonacci_5_0_0.pub \
--aligned_verification_data_path ~/.aligned/aligned_verification_data \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

5. You should get a response like this:

```bash
[2024-07-01T19:17:54Z WARN  aligned] Missing keystore used for payment. This proof will not be included if sent to Eth Mainnet
[2024-07-01T19:17:54Z INFO  aligned] Submitting proofs to the Aligned batcher...
[2024-07-01T19:19:18Z INFO  aligned] Batch inclusion data written into ./aligned_verification_data/e367d76e_0.json
[2024-07-01T19:19:18Z INFO  aligned] Proofs submitted to aligned. See the batch in the explorer:
[2024-07-01T19:19:18Z INFO  aligned] https://explorer.alignedlayer.com/batches/0xe367d76e832edec893d3a9027b3c231b2e3994c47acfac2e67197c13c9be0c4c
```

Use the link in the response to check the status of your transaction in the Aligned explorer.

6. After three Ethereum blocks, you should be able to check if it has been verified with the CLI using

```bash
aligned verify-proof-onchain \
--aligned-verification-data ~/.aligned/aligned_verification_data/*.cbor \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--network hoodi
```

This is reading the result of the proof verification in Ethereum.

7. You should get this result:

```bash
[2024-06-17T21:58:43Z INFO  aligned] Your proof was verified in Aligned and included in the batch!
```

If the proof wasn't verified, you should get this result:

```bash
[2024-06-17T21:59:09Z INFO  aligned] Your proof was not included in the batch.
```

Aligned works in:

* macOS Arm64 (M1 or higher)
* Linux x86 with GLIBC\_2.32 or superior (For example, Ubuntu 22.04 or higher)

If you don't meet these requirements, you can compile the binaries yourself following the [README](https://github.com/yetanotherco/aligned_layer)

To try Aligned with other proving systems, check [this](/guides/0_submitting_proofs) guide


# Use cases

Aligned’s ZK verification layer for Ethereum makes proof verification affordable, fast, and scalable—either via our low-latency [Proof Verification Layer](https://docs.alignedlayer.com/architecture/1_proof_verification_layer) (an EigenLayer AVS) or via our recursive [Proof Aggregation Service](https://docs.alignedlayer.com/architecture/2_aggregation_mode). Use Aligned when you need to verify many proofs, expensive proofs, or proofs that aren’t economical in the EVM, and you still want results settled to Ethereum.

The ZK verification layer can be useful anytime ZK is used with Ethereum, but some clear use cases are described in this section.

## ZK-rollups and Ethereum scaling

Rollups produce ZK proofs of state transitions and need to verify (settle) those results on Ethereum. Verification can cost ZK-rollup operators millions per year, and infrequent verification to save on gas leads to longer exit windows and worse UX.

### **How Aligned helps:**

* Offloads verification to a decentralized operator set, reducing per-proof gas by 90–99% and increasing throughput from \~tens of proofs/sec on Ethereum to thousands.
* For full L1 security and no cryptoeconomic trust assumptions, aggregate many rollup proofs into a single recursive proof verified on Ethereum.
* Option to use the Proof Verification Layer or Proof Aggregation Service depending on security and latency needs.

### **Choose a mode:**

* **Verification Layer (low latency, high volume):** live on mainnet; ideal for the fastest confirmations and very high proof volumes. Economic security with nearly 3 million restaked ETH (>$12B USD value).
* **Aggregation Service (highest security):** recursively compresses many proofs into one proof verified on L1; great when you can trade latency for full Ethereum security.

{% hint style="success" %}
Our RaaS makes launching [based ZK-rollups](https://blog.alignedlayer.com/aligned-raas-based-rollups-to-build-the-future-of-ethereum/) (Ethrex stack) possible in one click and is integrated with our ZK verification layer to reduce costs.
{% endhint %}

## Fast, trust-minimized bridging & interoperability

Bridges and cross-chain systems verify source chain state/account proofs on the destination chain. We are also developing an intents and ZK-based fast interoperability protocol in-house to take full advantage of the ZK Verification Layer and to complement our RaaS platform.

### **How Aligned helps:**

* Verifies non-EVM-friendly proofs (e.g., Kimchi, STARKs) economically and at scale.
* Enables fast exits (soft finality) while optionally posting hard-finality checkpoints via aggregation.

### **Choose a mode:**

* **Verification Layer** for quick attestations and user UX.
* **Aggregation Service** for periodic consolidated checkpoints to L1.

{% hint style="success" %}
The Mina ↔ Ethereum bridge uses Aligned to verify Mina’s Kimchi proofs on Ethereum ([blog post](https://blog.alignedlayer.com/mina-to-ethereum-bridge/)).
{% endhint %}

## zkTLS & web2-to-web3 data credentials

Generate proofs about data fetched over TLS (bank account balances, KYC, social graphs) and use them onchain without revealing the raw data.

### **How Aligned helps:**

* Turns high-volume zkTLS attestations into a practical UX by keeping verification costs low and parallelizable.
* Lets apps pick latency vs. finality per flow (e.g., instant gating on Verification Layer + periodic L1-final checkpoints via aggregation).

### **Choose a mode:**

* **Verification Layer** when users need instant attest-and-act.
* **Aggregation Service** when proofs must be verified directly on Ethereum.

## Verifiable AI (zkML / LLM inference proofs)

To make AI verifiable, prove that model inference (or parts of a pipeline) ran correctly, or that an output meets policy constraints—then settle the result to Ethereum for auditability or onchain automation.

### **How Aligned helps:**

* zkVM proofs from systems like SP1 and Risc0 are supported today, so you can move from POCs to production-grade verification economics.
* High-volume inference checks (micro-payments, agent marketplaces, model-usage attestations) benefit from the Verification Layer’s low latency; compliance/events can use aggregated L1 proofs.

### **Choose a mode:**

* **Verification Layer** for per-inference confirmations and low cost at scale.
* **Aggregation Service** for periodic, L1-final attestations (e.g., job batches, epoch summaries).

{% hint style="success" %}
See our [blog post](https://blog.alignedlayer.com/the-era-of-ai-needs-ethereum-and-zk/) that expands on why we believe ZK and Ethereum will play a major role in the future of AI.
{% endhint %}

## Identity & verifiable credentials

Issue/verify privacy-preserving credentials (DID/VC, age/eligibility proofs, reputation). Governments and enterprises can adopt ZK without forcing users to leak data.

### **How Aligned helps:**

* Makes credential verification cheap enough for mainstream UX while keeping Ethereum as the root of trust and avoiding the compromise of verifying proofs on a blockchain with lower security.
* Already powering real identity stacks (e.g. [Sovra’s Digital Trust Stack](https://blog.alignedlayer.com/aligned-sovra-partner-to-power-digital-trust-in-latin-america/)).

### **Choose a mode:**

* **Verification Layer** for interactive UX (logins, access control).
* **Aggregation Service** for archival or cross-period consolidated attestations.

## ZK coprocessors & oracles

Off-chain processes fetch data or perform heavy computations and return a ZK proof that onchain logic can trust. Allows offchain computation to be secured by onchain trust, giving smart contracts greater expressivity.

### **How Aligned helps:**

* Lets you run richer computations and affordably verify them onchain.
* A natural way to add computational trust and reduce L1 gas bottlenecks for oracle-like systems.

### **Choose a mode:**

* **Verification Layer** for frequent or streaming tasks.
* **Aggregation Service** when the highest security is needed (e.g. if the economic security from the AVS does not meet risk management parameters).

## Onchain gaming & interactive apps

Games and interactive dapps that prove game validity, scores/results, or anti-cheat logic with ZK.

### **How Aligned helps:**

* Low-latency verification makes regular and frequent proving economical.
* We’ve highlighted early builders in our [hackathon spotlights](https://blog.alignedlayer.com/tag/hackathons/).

{% hint style="success" %}
***Coming soon:*** Our **ZK Arcade** (launching 2025 Q3) will let users verify proofs of game results using Aligned.
{% endhint %}

## Which mode should I pick?

**Need the lowest cost and fastest confirmations?**

* Start with the [Proof Verification Layer](https://docs.alignedlayer.com/architecture/1_proof_verification_layer). It’s live on mainnet, secured by 52 restaked operators, and can verify thousands of proofs per second with results readable on Ethereum within blocks (cryptoeconomic security derived from Ethereum).

**Need full L1 finality in one transaction?**

* Use the [Proof Aggregation Service](https://docs.alignedlayer.com/architecture/2_aggregation_mode). It recursively compresses many proofs into one that’s verified directly on Ethereum, trading minutes of latency for the strongest security (full cryptographic security of Ethereum).

***You can also combine both:*** use the Verification Layer for UX and fast exits, then periodically post aggregated checkpoints for L1 finality.

The Proof Aggregation Service is a standalone service, independent from the Proof Verification Layer. Developers submit their ZK proofs directly to the Aggregation Service, where they are aggregated into a single recursive proof that is then verified on Ethereum. By aggregating many proofs into one, the cost of on-chain verification is amortized across the batch. Users can choose either the Verification Layer or the Aggregation Service depending on their latency and security requirements.

![Comparison between the Proof Verification Layer and Proof Aggregation Service (August 2025)](/files/02csDgvYQIbHshbUqN09)

## Supported proof systems

Aligned supports multiple verifiers (today: Risc0, SP1, gnark Groth16/Plonk, Circom, with more on the roadmap), so you can pick the right proving stack and still get good economics.

## Featured projects & posts

* [Verification Layer vs. Aggregation Service deep-dive](https://blog.alignedlayer.com/proof-verification-layer-vs-aggregation-service/)
* [Aligned RaaS: Based ZK-rollups using Ethrex](https://blog.alignedlayer.com/why-is-aligned-using-ethrex-for-based-zk-rollups/)
* [Mina ↔ Ethereum bridge](https://blog.alignedlayer.com/mina-to-ethereum-bridge/)
* [Why based rollups?](https://blog.alignedlayer.com/aligned-raas-based-rollups-to-build-the-future-of-ethereum/)

## Future additions

* Use cases: Aligned RaaS
* Use cases: Meta-proving services
* Use cases: Aligned Wallets-as-a-Service
* Use cases: Aligned Interoperability protocol


# FAQ

### What is Aligned's objective?

Aligned is creating the foundation for a trustless, verifiable internet. Our vertically integrated stack empowers developers to build applications across finance, AI, and other sectors with one-click solutions for wallets, rollups, and zero-knowledge services on Ethereum. We’re focused on enabling provable execution in a world where institutional trust is increasingly fragile.

By providing the tools for trust to be integrated into every layer of application infrastructure, we’re enabling developers to create verifiable systems that can be trusted across a wide range of use cases. Aligned is here to enable a future where trust is not assumed, but proven by design.

### What are the security guarantees and trust assumptions of Aligned's Proof Verification Layer?

Aligned's Proof Verification Layer verifies proofs by having the operators re-execute the verification code for each proof and, if all of the proofs are valid, each of them signs a message containing a commitment to the proof and public input or the root of the batch. The aggregator is responsible for receiving the signatures, checking the quorum, performing the aggregation and sending them to Ethereum.

* 67% of the operators behaving dishonestly to be able to submit false proofs.
* 33% of the operators colluding to censor a batch of proofs or task. However, in the case of a batch, the operators can only censor the whole batch, but not a particular proof included in it.
* The aggregator can censor batches or proofs by not sending the aggregated signature.

### What is the batcher?

We have a service called the Batcher that batches enough proofs to send to the AVS in EigenLayer to reduce on-chain verification costs. Users can submit their proofs directly to Aligned’s Proof Verification Layer without using the Batcher. The Batcher is fully optional and serves as an optimization to further reduce on-chain verification costs.

### What are the security guarantees added by the batcher?

A batcher can censor proofs. The user can run their own batcher to avoid censorship or can send a task to verify proofs in our Proof Verification Layer via Ethereum without using the batcher. The batcher cannot transfer user's funds to other accounts, only spend them to create verification tasks and pay to the aggregator. We recommend depositing only enough funds for a few months of operations.

### How do I send proofs without a batcher?

You can see the steps to do it in [this guide](/guides/9_submitting_batch_without_batcher).

### How do I run my own batcher?

To-do

### Why build Aligned on top of Ethereum?

Ethereum is the most decentralized and most significant source of liquidity in the crypto ecosystem. We believe it is the most ambitious and long-term project on the internet. Aligned is being built to help Ethereum achieve its highest potential, and we believe this is only possible through validity/zero-knowledge proofs.

For further reading on this subject, you can refer to [this Aligned blog post](https://blog.alignedlayer.com/why-ethereum/), which explains why we chose Ethereum.

### What is the throughput of Aligned’s Proof Verification Layer?

Aligned’s Proof Verification Layer runs the verifier’s code natively. The verification time depends on the proof system, program run, and public input. Generally, most verifiers can be run in the order of ms on consumer-end hardware. We can optimize the code for speed and leverage parallelization by running it natively. Current testnet can verify more than 2500 proofs per second.

### How does the throughput of Aligned’s Proof Verification Layer compare with Ethereum?

Ethereum runs on top of the EVM. Each block is limited to 45,000,000 gas. Since the most efficient proof systems take at least 250,000 gas, Ethereum can verify 180 proofs per block. Aligned's Proof Verification Layer runs the code natively and leverages parallelization, reaching 30,000 proofs in the same period.

### Why is Aligned buiding its stack?

Aligned is building its stack to provide the infrastructure for a trustless, verifiable internet. Its vertically integrated stack enables developers to create applications across industries like finance and AI, with one-click solutions for rollups, wallets, and several zero-knowledge (ZK) services. Innovations in proving virtual machines, like Risc0, Jolt, SP1, and Valida, allow users to generate proof of computation integrity using languages like Rust or C. However, Ethereum’s proof verification is costly and slow, limiting innovation. Aligned addresses this with its Proof Verification Layer and Proof Aggregation Service, reducing verification costs and increasing throughput. In addition, Aligned offers a Wallet-as-a-Service infrastructure for simplifying wallet generation, and a Rollup-as-a-Service (RaaS) platform for easy ZK-rollup deployment. Its Interoperability Protocol also supports trust-minimized cross-chain liquidity movement. Together, these innovations aim to build a scalable, secure, and trustless internet.

### Is Aligned an Ethereum L2?

No. Aligned is a vertically integrated stack for building applications on a verifiable internet. However, our stack offers one-click solutions for rollups, as well as wallets, and several ZK services.

### How much it cost to verify proofs using Aligned's Proof Verification Layer?

The cost ($C$) of proof verification using Aligned's Proof Verification Layer is the cost of task creation ($C\_{task}$) plus the cost of verifying an aggregated BLS signature ($C\_{verification}$), divided by the number of proofs ($N$) in the batch, plus the the cost of reading the results on-chain ($C\_{read}$).

$$
C =\frac{C\_{task} + C\_{verification}}{N} + C\_{read}
$$

The cost of task creation and signature verification is amortized across $N$ proofs per batch, meaning that our verification layer becomes cheaper to use as more proofs are verified at the same time.

### What are BLS signatures?

[Boneh-Lynn-Shacham (BLS)](https://en.wikipedia.org/wiki/BLS_digital_signature) signatures are a cryptographic signature that allows a user to verify that a signer is authentic. It relies on elliptic curve pairings and is used by Ethereum due to its aggregation properties.

### Why do you have a Proof Verification Layer and a Proof Aggregation Service?

The Proof Verification Layer is designed to offer very cheap verification costs and low latency. It uses crypto-economic guarantees provided by restaking; costs can be as low as 2100 gas. The Proof Aggregation Service uses recursive proof aggregation, achieving the complete security of Ethereum, but with slightly higher fees and latency. We verify an aggregated BLS signature (around 113,000 gas) in our Proof Verification Layer. We verify an aggregated proof (around 300,000 gas) in our Proof Aggregation Service. Together, these two services form our ZK verification layer which offers developers different options for reducing proof verification costs on Ethereum, depending on their scale and security requirements.

### What is proof recursion?

Zero-knowledge proofs let you generate proofs that show the correct execution of programs. If a program is the verification of a proof, then we will be getting a proof that we verified the proof and the result was valid. The validity of the second proof implies the validity of the original proof. This is the idea behind proof recursion, and it can be used with two main goals:

1. Convert one proof type to another (for example, a STARK proof to a Plonk proof) either to reduce the proof size, have efficient recursion, or because the proof system cannot be verified where we want.
2. Proof aggregation: if we have to verify $N$ proofs on-chain, we can generate a single proof that we verified the $N$ proofs off-chain and just check the single proof on Ethereum.

Proof recursion is the primary tool used by Aligned’s aggregation mode.

### What is restaking?

EigenLayer introduced the concept of Restaking. It allows Ethereum’s validators to impose additional slashing conditions on their staked ETH to participate in Actively Validated Services (AVS) and earn additional rewards. This creates a marketplace where applications can rent Ethereum's trust without competing for blockspace. Aligned's fast mode is an AVS.

### Is Aligned an aggregation layer?

Aligned provides proof aggregation as part of its Proof Aggregation Service, a feature shared with all aggregation layers. However, Aligned offers a unique Proof Verification Layer designed to provide cheap and low-latency proof verification, secured by restaked ETH.

### What proof systems do you support?

Aligned’s stack is designed to support any proof system. [Currently supported ones](/architecture/0_supported_verifiers) are Groth16 and Plonk (gnark), SP1, Risc0, and Circom.

### How does Aligned's Proof Verification Layer work?

The flow is as follows:

1. The user uses a provided CLI or SDK to send one proof or many to the batcher, and waits (Alternatively, the user can run a batcher or interact directly with Ethereum)
2. The batcher accumulates proofs of many users for a small number of blocks (typically 1-3).
3. The batcher creates a Merkle Tree with commitments to all the data submitted by users, uploads the proofs to the Data Service, and creates the verification task in the ServiceManager.
4. The operators, using the data in Ethereum, download the proofs from the DataService. They then verify that the Merkle root is equal to the one in Ethereum, and verify all the proofs.
5. If the proofs are valid, they sign the root and send this to the BLS signature aggregator.
6. The signature aggregator accumulates the signed responses until reaching the quorum, then sends the aggregated signature to Ethereum.
7. Ethereum verifies the aggregated signatures and changes the state of the batch to verified.

### How can I verify proofs using Aligned's stack?

You can verify proofs with our stack using our CLI or Rust SDK.

### Can you provide an estimate of Aligned’s savings?

Proof verification directly on Ethereum (not including the cost of accessing/reading) costs:

* Groth 16 proofs: >250,000 gas
* Plonk/KZG proofs: >300,000 gas
* STARKs: >1,000,000 gas
* Binius/Jolt: too expensive to run!

With Aligned's Proof Verification Layer:

* Just one proof (any!): 350,000 gas
* Batching 1024 proofs: 350 gas + reading cost

This means verifying proofs using Aligned's Verification Layer can be 99% cheaper than directly on Ethereum.

### I want to verify just one proof. Can I use your products and services for cheap and fast verification?

Yes! And all proofs cost the same to verify using our stack.

### Is Aligned open-source?

Yes! We are 100% open-source from day one.

### What’s the role of Aligned in Ethereum?

Aligned's role is to provide a full stack of vertically integrated infrastructure that simplifies the process of launching, operating, and scaling on the Ethereum network, enabling teams to build applications across finance, AI, and other sectors with one-click solutions for wallets, rollups, and zero-knowledge services.

### Why do we need a ZK verification layer?

Verifiable computation allows developers to build applications that help Ethereum scale or even create applications that were not possible before, with enhanced privacy properties. We believe the future of Ethereum will be shaped by zero-knowledge proofs and our goal is to help increase its capabilities.

### What are the use cases for Aligned's stack?

We believe that there are many things that will be built using Aligned's stack that we have not even imagined yet. For some possible use cases please see [this page](/introduction/2_use_cases).

### Why EigenLayer?

We believe Ethereum is the best settlement layer, and ZK will play a key role in helping it become the settlement layer of the internet. We want to build a verification layer that helps Ethereum achieve this goal. This layer needs to have a decentralized group of validators that will just re-execute the verification of different proofs: so how do we build such a decentralized network that will help Ethereum?

Creating a new L1 doesn’t benefit Ethereum because it will add new trust assumptions to the Ethereum protocols relying on it. EigenLayer enables Aligned to have the following properties:

1. A decentralized network of verifiers
2. A similar economic security level that can be easily measured in ETH
3. Part of the Ethereum ecosystem
4. Flexible enough to support many current and future proving systems

### What about TEEs?

Aligned's stack will also verify remote attestations made by Trusted Execution Environments (TEEs). We believe TEEs provide an alternative to ZK in some applications where ZK is too computationally intensive or as an additional mechanism to provide integrity (*e.g.* in multiproofs).


# Why ZK and Aligned?

The following is an introduction to zero-knowledge/validity proofs to understand their utility and impact and why they may help you solve problems you can encounter when building your application. Before jumping on the explanation, we give some definitions:

* Validity/integrity proofs: These are cryptographic proofs that allow you to check that a computation was carried out correctly, without having to re-run it entirely.
* Zero-knowledge proofs: These are cryptographic that allow you to prove the validity of a statement, without revealing sensitive data.

The two terms are sometimes grouped under ZK, though depending on the use case, you may need it to be zero-knowledge or not. Validity proofs are widely used by ZK-rollups (though not rigorously zero-knowledge), while Schnorr signatures are an example of the second (basically, they let you show to others that you have a secret key, without leaking it).

In blockchains, we need to coordinate between different parties that do not trust each other. How can we agree on whether something has happened? The logical construction involves independently re-executing transactions and reaching consensus. However, the number of transactions we can process is limited by the weakest devices in the network, acting as bottlenecks. Moreover, adding more hardware does not make the system faster (as in web2), only more robust. ZK allows the situation to scale, allowing the system to process more transactions with the same guarantees. ZK proofs allow you to verify a computation much faster than re-execution: we can use more powerful machines to run the transactions and generate the cryptographic proof, and the rest of the network verifies the proof. If the proof is valid, it is the same as if all the nodes had re-executed the transactions, but with less computational effort. More concretely, a ZK-rollup can generate a proof that it processed 10,000 transactions correctly, and submit to Ethereum the proof with the state diff (or other information necessary to update the state), and Ethereum can check very quickly that all those transactions were correct! ZK is also useful whenever you need to show the integrity of some computation, for example, that an image you published in the newspaper is the result of enlarging an image from a real camera. This is where Aligned's stack comes in.

With Aligned's stack, you can generate the proof and then use Ethereum as a settlement layer. To do so, Aligned offers a variety of products to reduce your costs and increase throughput. Once you decide to use ZK for your product and Ethereum, Aligned fits perfectly.

* **Proof Verification Layer:** A decentralized network of verifiers that checks the proofs, signs messages stating the correctness of the proof and when a threshold is met, publishes the signature to Ethereum. Once Ethereum checks the signature, the state of the proofs is changed to verified, and you can use the result as always. It has very high throughput, reduces costs significantly (depending on the number of proofs that are sent) and has low latency.
* **Proof Aggregation Service:** Performs recursive proof aggregation of several ZK proofs. The final proof is sent to Ethereum, and if verified, it implied the validity of your proof. It has higher latency and lower throughput than the proof verification layer, but achieves the full security of Ethereum.
* **Meta Proving Services**: Offers an easy interface for accessing centralized and decentralized proving from external providers.
* **Rollup-as-a-service (RaaS) platform:** Simplifies ZK-rollup deployment, allowing clients to launch L2 chains with just one click, without needing deep blockchain expertise.
* **Interoperability protocol:** An intent-based bridge that will be integrated with our RaaS stack. It will leverage based sequencing and enable developers to create native trust-minimized solutions for users and financial institutions to efficiently move liquidity across chains.
* **Wallet-as-a-Service infrastructure:** Enable developers to easily generate embedded wallets for users, supporting rollups and mobile integrations. It will leverage the latest account abstraction technology, offering seamless wallet services backed by our robust tech stack.

How can you write ZK applications and generate proofs? There are many different technologies and libraries to build ZK applications. Until recently, it was fairly complicated, since you needed some background of math and write circuits (you can think of it as coding in assembly). Luckily, there are several ZK virtual machines (zkVM) that allow you to generate proofs of code written in a higher level language, such as Rust. You write your code and run it on top of the zkVM, and you get a proof of its correct execution. To simplify things, we have [zkRust](/guides/5_using_zkrust), where you can run your code and send the proof directly to Aligned!

## Projects or ideas using ZK

The list below contains examples or projects using ZK. It is meant to illustrate some use cases, but it is not meant to be exhaustive.

* Rollups
* On-chain gaming
* ZK Machine Learning (zkML)
* ZK-TLS
* Bridges
* Oracles
* Data processors
* Voting
* ZK-Email
* Identity protocols
* IoT


# Supported Verifiers

Aligned's support for multiple proof systems is a significant advantage, as it allows users to choose the most suitable system based on their specific requirements.

The following is the list of the verifiers currently supported by Aligned:

* :white\_check\_mark: gnark - Groth16 (with BN254) [(v0.12.0)](https://github.com/Consensys/gnark/releases/tag/v0.12.0)
* :white\_check\_mark: gnark - Plonk (with BN254 and BLS12-381) [(v0.12.0)](https://github.com/Consensys/gnark/releases/tag/v0.12.0)
* :white\_check\_mark: SP1 [(v5.0.0)](https://github.com/succinctlabs/sp1/releases/tag/v5.0.0)
* :white\_check\_mark: Risc0 [(v3.0.3)](https://github.com/risc0/risc0/releases/tag/v3.0.3). Previous versions are also compatible.
* :white\_check\_mark: Circom [(v2.2.2)](https://github.com/iden3/circom/releases/tag/v2.2.2)
* :white\_check\_mark: Mina (Testnet only - Sepolia, Hoodi)
* :white\_check\_mark: Mina Account (Testnet only - Sepolia, Hoodi)
* 🏗️ Lambdaworks
* 🏗️ Kimchi

The following are in the roadmap to be added:

* :black\_square\_button: Jolt
* :black\_square\_button: Nexus


# Key Terms

## Proof

A **Proof** is cryptographic data that can attest to the validity of a given computation. The concrete data and size depend on the proof system and program used.

## Verification

The **Verification** is an algorithm that takes the proof, and associated public data and verification key/program and outputs whether the proof is valid or not.

## Proof Batch

A **Proof batch** is a collection of verification tasks to be carried out by the Operators.

## User CLI

The **User CLI** is used to interact with the Verifier Task Batcher. It sends proof and public input data and receives the verification data in Aligned.

## Verifier Task Batcher

The **Verifier Task Batcher** receives tasks from users, creates batches of tasks, publishes the proof and public data in the Data service, and sends the batches’ data to Ethereum. This service is permissionless, meaning users have the option to run their own batcher.

## Service Manager

The **Service Manager (Ethereum smart contract)** receives the batches’ data and signatures from the BLS signature aggregator. This contract provides information to validators and Light Clients on the batches/tasks.

## Data Service

The **Data Service** temporarily stores the data for the proof and public input.

## Operators

The **Operators** are responsible for performing the verification of the proofs in each batch and signing messages with the results.

## BLS Signature Aggregator

The **BLS Signature Aggregator** receives the signatures from the Operators, checks if a quorum is reached, if so, it performs the aggregation of the signatures.

## Light Clients

The **Light Client** samples random tasks from the Service Manager, checks the proofs, and compares against the results posted to Ethereum by Aligned. If there are differences, it can trigger an L1 verification via the proof service. In case of malicious behavior by Aligned’s Operators, this would lead to slashing.

## Proof Service

The **Proof Service** receives results from the Light Clients; in case there are differences with the results posted by Aligned, it triggers a re-verification on Ethereum. Note that this re-verification can also be triggered by any user.

## Proof Aggregator

The **Proof aggregator**, once tasks have been verified by Aligned’s Operators, performs recursive proof verification to create one proof that will attest to the validity of all proofs contained in the batch. This proof is verified on-chain.


# Proof Verification Layer

### Aligned's Proof Verification Layer in a nutshell

Aligned's Proof Verification Layer works using a subset of Ethereum’s validators via restaking. Validators (also called Operators) receive proofs, verify them using the verification code written in Rust or another higher-level language, and sign messages with BLS signatures. If a two-thirds majority agrees, the results are posted to Ethereum.

### Simplified Architecture

The proof submission can be simplified as follows:

![Figure 1: Simplified Architecture](/files/2oqQjoW9whXR6JYnaN93)

1. The users submit proofs to the batcher through the CLI or SDK.
2. The batcher accumulates proofs, and then sends the batch to some Data Service and posts the merkle root and data to Ethereum.
3. The operators download the proofs from the Data Service, verify them, and sign the results.
4. The BLS signature aggregator accumulates the signed responses until reaching the quorum, then sends the aggregated signature to Ethereum.
5. The users can read the results from Ethereum.

### Architecture

Aligned’s architecture is shown in the figure below:

![Figure 2: Proof Verification Layer Architecture](/files/ZQSQxn2DiAgTkaIu55s7)

The validators/AVS operators are the ones responsible for proof verification. They fetch the proof data from the data service and verify it using the different proving systems supported by Aligned.

#### What happens when sending a proof and publishing the result on Ethereum?

The flow for sending a proof and having the results on Ethereum is as follows:

1. The user uses a provided CLI or SDK to send one or many proofs to the batcher, and waits.
2. The batcher answers with a ValidityResponse for each proof (if proof, nonce and signature are valid).
3. The batcher answers with a BatchInclusionData for each proof.
4. The user invokes the VerifyBatchInclusion function in the ServiceManager contract with this data to check that the proof has been verified in Aligned and is included in the batch.
5. Then, it is checked that the commitment of the proven program matches the expected one.

#### Full flow with internals of the proof

1. The user uses a provided CLI or SDK to send one or more proofs to the batcher, and waits (Alternatively, the user can run a batcher or interact directly with Ethereum).
2. The batcher accumulates proofs of many users for a small number of blocks (typically 1–3).
3. The batcher creates a Merkle Tree with commitments of all the data submitted by users, uploads the proofs to the Data Service, and submits it to the [Batcher Payment Service](/architecture/1_proof_verification_layer/2_payment_service_contract)
4. The Batcher Payment Service rebuilds the merkle tree, and then verifies user signatures and nonce's.
5. The Batcher Payment Service sends the batch to the [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract).
6. The operators, using the data in Ethereum, download the proofs from the DataService. They then verify that the Merkle root is equal to the one in Ethereum, and verifies all the proofs.
7. If the proofs are valid, they sign the root and send this to the BLS signature aggregator.
8. The signature aggregator accumulates the signed responses until reaching the quorum, then sends the aggregated signature to Ethereum.
9. Ethereum verifies the aggregated signatures and changes the state of the batch from pending to verified.

#### Batch structure

The task batch consists of a Merkle tree containing the relevant information for proof verification in the lower level leaves. The root of the Merkle tree is posted to Ethereum together with a pointer to where the data is stored. Each leaf contains the following information:

* A commitment to the public input of the proof.
* A commitment to the proof
* A commitment to the program or a commitment to the verification key, plus the Proving System/verifier used.
* The address of the proof’s generator/submitter (optional).

A diagram for the batch is shown on the figure below:

![Figure 3: Structure of a batch](/files/3QLK2FUckE99pghsRTai)

#### Reading the results from Ethereum

Once the results from a batch have been checked on Ethereum, the Aligned contract is updated with the results. The user’s contract can query the Aligned contract to check whether the proof has been included in a successful batch.

Additionally, the contract needs to be set to receive only proofs of specific programs. For example, in an L2, this may be a specific program that represents the state transition of the blockchain. In the contract, the pseudocode would look like this:

```
is_verified = VerifyWithAlignedVerificationData(
   AlignedVerificationData
)
require(is_verified)
require(ProofVerificationData.ProgramComm ==...)
```

Optionally, a committed address can also be used, an example being if one wants to give an NFT or tokens to a user that submitted a proof. Depending on the application, it may be needed or not.

### Entities

Aligned has the following entities:

![Figure 4: Entities](/files/OcLTf5KFraOMFnhDqcxk)

All entities are described in the next sections.


# Batcher

The Batcher receives proofs from different Users, bundles them in a batch of proofs, builds a Merkle Root from these, uploads the batch to a data service (like an S3 bucket), and submits this information to the [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract).

To ensure that the User can be certain that their proof was included in a batch, the Batcher will send each User their Merkle Proof (or Merkle Path). With this, the User can rebuild the Merkle Root starting from their proof, thus verifying it was actually included in the batch.

Also, to avoid unnecessary proof submissions, the Batcher performs preliminary verifications of the submitted proofs in to minimize the submission of false proofs in a batch.

However, each proof has a cost of verification, so each batch must contain some sort of payment for it to be verified. To handle the payment for each batch, the Batcher submits the batch through its [Batcher Payment Service](/architecture/1_proof_verification_layer/2_payment_service_contract).

To send the batch of proofs to the [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract), the Batcher stores the batch of proofs in an S3 for 1 week, and sends the link to the file to the [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract).

To view how to submit your own batch, without the use of this Batcher, you may follow [the following guide](https://github.com/yetanotherco/aligned_layer/blob/testnet/docs/3_guides/8_submitting_batch_without_batcher.md)

### Max fee priority queue

The batcher queue is now ordered by `max_fee` signed by users in their proof messages - the ones willing to pay more will be prioritized in the batch.

Because of this, a user can't have a proof with higher nonce set with a higher fee included in the batch. For example, consider this situation in a batch. Let the two entries in the batch be from the same address:

```
[(nonce: 1, max_fee: 5), (nonce: 2, max_fee: 10)]
```

This shouldn't happen because it would make the message with higher nonce be processed earlier than the one with a lower nonce, hence it will raise an invalid nonce error.

When a user submits a proof for the first time in the batch, its `max_fee` is stored and set as the `user_min_fee` for the rest of the proofs to be included in the batch. It is called this way because it means the minimum fee a user has sent. If a later message with a higher `max_fee` is received, the message is rejected and not included in the queue, while if a message with a lower `max_fee` is received, the message is included in the queue and the `user_min_fee` is updated to that value. In summary, **no messages with a higher `max_fee` than the `user_min_fee` will be included**.

In case a message has a `max_fee` that is too low - allowing it to be stuck in the batcher's queue, the message can be re-sent (called *replacement message*) to bump its `max_fee` with a higher fee. For this, a validation is done first. We check that when the `max_fee` for the message with that nonce is updated, there is no message with a lower nonce and a lower `max_fee`, because this would lead to the problem of messages with higher nonce processed earlier than messages with lower nonce, as discussed earlier. As an example, consider all these messages in a batch from the same address:

```
[(nonce: 1, max_fee: 10), (nonce: 2, max_fee: 5), (nonce: 3, max_fee: 3)]
```

If the user wants to send a replacement message for the message with nonce 2, updating the max fee to 11, it wouldn't be valid. But it could update the max fee to, for example, 8.

## Batch finalization algorithm

There are some analogies in the processing of the batch with respect to how Ethereum handles transactions in the mempool and builds blocks. We can consider the Batcher priority queue as a sort of *mempool* in the Ethereum case. Once certain conditions are met, the Batcher will try to make a *finalized batch*, containing the maximum amount of highest paying messages, which in the analogy is like assembling a block in Ethereum, grabbing the highest valued transactions.

When the conditions to build a batch are met, the Batcher runs the following batch finalization algorithm to create a batch of proofs from the priority queue.

This algorithm starts by calculating the **batch size**, in bytes, by adding the verification data bytes of each proof of the queue. The next step is to build a new **resulting priority queue**, which will store all proofs that where not included in the batch, replacing the current priority queue when this algorithm ends.

In order for the batch to be considered valid, two conditions have to be met:

* The **batch size** in bytes must be less than or equal to a defined limit.
* All proofs found in the batch must have a `max_fee` equal or higher to the calculated **fee per proof** of the batch.

The **fee per proof** indicates the cost of verifying each proof within the batch. It is calculated using a formula that depends on the **batch length**, defined as the number of proofs in the batch:

```
gas_per_proof = (constant_gas_cost + additional_submission_gas_cost_per_proof * batch_len) / batch_len
fee_per_proof = gas_per_proof * gas_price
```

Since the priority queue is sorted in ascending order of `max_fee`, we can be certain that if the proof with the smallest `max_fee` complies with the **fee per proof** rule, then all remaining proofs in the queue will do so

```
priority_queue = [(proof_a, 87), (proof_b, 90), (proof_c, 99)]
```

The algorithm attempts to build new batch by iterating on each proof, starting with the one with the smallest `max_fee` in the queue. On each iteration, the **batch size** and **fee per proof** will be recalculated and both conditions reevaluated. When both conditions are met, all proofs remaining in the queue will be used to build the new batch. The remaining proofs, stored in the **resulting priority queue**, will be candidates to the next batch finalization algorithm execution.

So, instead of the batcher "building" a batch by adding valid messages, it builds a batch by gradually not considering the cheapest ones, until a valid one is found.

There is an edge case for this algorithm: If the fee per proof is too high even for the highest `max_fee` proof, the algorithm will iterate over each proof until the **priority queue** is empty. This means no proof allowed enough `max_fee` to be included in a batch. If this happens, the finalization of the batch is suspended and all the process will start again when a new block is received.

Let's see a very simple example, the algorithm starts with the following state:

```
priority_queue = [(E, 74), (D, 75), (C, 90), (B, 95), (A, 100)]
resulting_priority_queue = []
max_batch_size = 1000 # Defined constant
```

On the first iteration, the proof with the smallest `max_fee` is taken and the **fee per proof** is calculated

```
priority_queue = [(E, 74), (D, 75), (C, 90), (B, 95), (A, 100)]
resulting_priority_queue = []
current_proof = (E, 74)
fee_per_proof = calculate_fee_per_proof(priority_queue) # Result: 70
batch_size_bytes = calculate_batch_size(priority_queue) # Result: 1150
```

This batch can't be finalized, since it exceeds the maximum batch limit of 1000 bytes. This proof will be discarded for the current batch and stored in the **resulting priority queue**

```
priority_queue = [(D, 75), (C, 90), (B, 95), (A, 100)]
resulting_priority_queue = [(E, 74)]
current_proof = (D, 75)
fee_per_proof = calculate_fee_per_proof(priority_queue) # Result: 76
batch_size_bytes = calculate_batch_size(priority_queue) # Result: 990
```

This batch won't be finalized either, since the **fee per proof** of the batch is higher than the `max_fee` of the current proof. This proof will be discarded for the current batch and stored in the **resulting priority queue**

```
priority_queue = [(C, 90), (B, 95), (A, 100)]
resulting_priority_queue = [(E, 74), (D, 75)]
current_proof = (C, 90)
fee_per_proof = calculate_fee_per_proof(priority_queue) # Result: 90
batch_size_bytes = calculate_batch_size(priority_queue) # Result: 850
```

All proofs in this batch comply with the `max_fee` and **fee per proof** condition, and the batch size is lower than the established limit, so this batch will be finalized!

The execution ends with the following state for the batcher: a new batch is created , and the **priority queue** is replaced by the **resulting priority queue**

```
new_batch = [A, B, C] # Batch to send
priority_queue = [(E, 74), (D, 75)] # New priority queue
```


# Payment Service Contract

The Payment Service handles users payments to fund the verification of their proofs.

To be able to use the batcher, a user must fund its transactions. For this, there is a simple Payment Service.

The Batcher has an associated `Batcher Payments` smart contract, which is in charge of receiving user's payments, and it guarantees that it can only spend these funds to send users' proofs to Aligned.

Users must first deposit into this contract, via a normal transfer to its address, where the Batcher Payment System will update the User's balance.

Users send proofs to the Batcher, which checks whether there are enough funds. Once a batch is complete, the Batcher calls its smart contract with the collected user data

The smart contract deducts funds from senders' balances and creates a new Batch in the [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract), including funds for batch verification payment to the [Aggregator](/architecture/1_proof_verification_layer/5_aggregator).

Users can then withdraw extra funds deposited to the Batcher Payments smart contract, or leave them to fund future proofs. To avoid causing a Denial of Service on the Batcher, Users must first call the contract's `unlock` function, and then call `withdraw` at least 100 blocks later, to finish their withdrawal process. This enables the Batcher to be sure the User will have funds to pay for his proofs when `createNewTask` is called.

This way, the Batcher can only use the User's funds to pay for the verification of the User's proofs. The Batcher Payment Service guarantees that the Batcher will not be able to spend the user funds for anything other than submitting the user's proofs to Aligned.

## Payment service architecture and flow

![Payment Service Flow Diagram](/files/ij2syV4KBFZG4dXJTBNk)

## Details of the contract

### API

#### Receive funds

```solidity
    receive() external payable
```

This function will be called every time a User transfers funds to the smart contract. It will not only receive the funds, but it will also register internally how much the User deposited, to keep track of each User's funds separately.

#### Create New Task

```solidity
function createNewTask(
    bytes32 batchMerkleRoot,
    string calldata batchDataPointer,
    address[] calldata proofSubmitters,
    uint256 feeForAggregator,
    uint256 feePerProof,
    uint256 respondToTaskFeeLimit
) external onlyBatcher whenNotPaused
```

This function is called only by the Batcher when it has a batch ready to be submitted to Aligned. It contains all the information needed to post the batch in the [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract) (`batchMerkleRoot` and `batchDataPointer`), plus an array containing which are the `proofSubmitters`, to discount `feePerProof` from these, and also the `feeForAggregator`, declaring how much will need to go pay for the response of the batch, as well as the `respondToTaskFeeLimit`, a safeguard that sets the max quantity of Ethereum that the aggregator should spend in case of a gas price spike.

#### Unlock

```solidity
    function unlock() external
```

Any user can call this function to unlock its funds for withdrawal after 100 blocks.

Note that if the user funds are unlocked, the batcher will reject any new proofs from this user until the funds are locked again.

#### Lock

```solidity
    function lock() external
```

Any user can call this function to lock its funds again after unlocking.

#### Withdraw

```solidity
    function withdraw(uint256 amount) external
```

Any User can call this function to withdraw any amount of their available balance from the contract, only when their funds are unlocked.


# Service Manager Contract

The Aligned Service Manager handles the reception of new batches to Aligned, keeps their status on-chain, and receives their response.

It is a smart contract which receives all new batches, with their Merkle Root and a pointer to where the batch is currently stored. When received, this manager will emit an Event for the [Operators](/architecture/1_proof_verification_layer/4_operator) to know when there is a new batch to verify.

Then, when receiving a response from the [Aggregator](/architecture/1_proof_verification_layer/5_aggregator), with Operator's aggregated BLS signatures, the Aligned Service Manager checks the BLS signature to verify the Operators were in fact those who processed the batch and its responded status.

Once verified, it will emit another Event, for anyone interested (for example, the [Explorer](/architecture/1_proof_verification_layer/6_explorer)) to know that the batch was verified by the operators. This batch is now verified and Users can know their proofs inside the batch were proven and verified leveraging Ethereum's security.

## Details of the contract

Besides the base [EigenLayer middleware contracts](https://github.com/Layr-Labs/eigenlayer-middleware/tree/mainnet/src), the core contract for Aligned is [AlignedLayerServiceManager](https://github.com/yetanotherco/aligned_layer/blob/testnet/contracts/src/core/AlignedLayerServiceManager.sol). It is in charge of creating new batch verification tasks, storing batches state and verifying operator responses.

### API

#### Create new task

```solidity
function createNewTask(
    bytes32 batchMerkleRoot,
    string calldata batchDataPointer,
    uint256 respondToTaskFeeLimit
) external payable
```

This method is called to create a new batch verification task that will broadcast an event to all operators, signaling that there are new proofs awaiting verification.

* `batchMerkleRoot` is a 256 bit hash corresponding to the Merkle Root of the proofs batch to be verified by operators.
* `batchDataPointer` is a string representing a link to some specific data storage location. This is used by operators to download the entire batch of proofs.
* `respondToTaskFeeLimit` are the funds required for the operator to respond to the task

#### Respond to task

```solidity
function respondToTask(
    bytes32 batchMerkleRoot,
    address senderAddress,
    NonSignerStakesAndSignature memory nonSignerStakesAndSignature
) external
```

This method is used by the Aggregator once the quorum for a particular task has been reached. Its main purpose is to verify the aggregated signature of the operators for the given task, and also that the quorum was reached. After verifying, an event is emitted signaling to any consumer that the batch has reached soft finality.

* `batchMerkleRoot` is a 256 bit hash representing the Merkle Root of the batch that has been verified and signed by operators.
* `nonSignerStakesAndSignature` is a struct provided by EigenLayer middleware with information about operators' signatures, stakes and quorum for the given task.
* `senderAddress` is the address of the batcher that created the task being responded to.

### Verify batch inclusion

```solidity
function verifyBatchInclusion(
    bytes32 proofCommitment,
    bytes32 pubInputCommitment,
    bytes32 provingSystemAuxDataCommitment,
    bytes20 proofGeneratorAddr,
    bytes32 batchMerkleRoot,
    bytes memory merkleProof,
    uint256 verificationDataBatchIndex
) external view returns (bool)
```

A method used for consumers to check that their proof was verified in Aligned. It checks if the batch where the proof was included was verified and if the proof was included in the batch when verifying the Merkle path.

* `proofCommitment`, `pubInputCommitment`, `provingSystemAuxDataCommitment`, `proofGeneratorAddr` are the commitments to the verification data sent to the batcher.
* `batchMerkleRoot` is a 256 bit hash representing the batch Merkle Root the proof was included in.
* `merkleProof` is the Merkle path from the hashed leaf built from the verification data commitments to the root.
* `verificationDataBatchIndex` is the index of the proof in the batch where it was included.


# Operator

The Operators verify the ZK Proofs and are the Eigenlayer restakers. They also insert financial security into the system, and leverage Ethereum's security for any AVS they take part in (e.g. Aligned).

Operators read [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract)'s new batch events. These have the necessary information to verify a batch, its Merkle Root, and its data pointer.

With the data pointer, they will download the actual proofs they will need to verify. The first thing they do after this, is verify that the downloaded proofs actually compute the expected Merkle Root. If not, they will regard the batch as corrupted and will not verify it. This avoids malicious [Batchers](/architecture/1_proof_verification_layer/1_batcher) from uploading proofs that are different from what users uploaded.

After verifying the Merkle Root of the batch, thus verifying that the downloaded batch matches the one intended to be submitted, the Operator must now verify each one of its proofs. This is done by executing the appropriate verification programs integrated with Aligned.

After verifying the whole batch, Operators sign their response (either true or false depending on whether the batch was completely verified or not) with a BLS signature, and send it to the [Aggregator](/architecture/1_proof_verification_layer/5_aggregator).


# Aggregator

The Aggregator collects [Operator](/architecture/1_proof_verification_layer/4_operator)'s BLS Signatures.

When the quorum of responses is reached, the Aggregator will submit a Task Response with the aggregated signatures back to the [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract).


# Explorer

{% embed url="<https://explorer.alignedlayer.com>" %}

The Explorer keeps track of [Aligned Service Manager](/architecture/1_proof_verification_layer/3_service_manager_contract).

It has an internal state of previous batches, actively listens for new batches and their responses. The Explorer then displays this information for Users to visualize the submitted batches, their states and more useful information in real time.

In the landing page, we can see information such as how many [Operators](/architecture/1_proof_verification_layer/4_operator) are currently registered and active, total ETH restaked by said Operators, how many Batches and how many total Proofs have been verified.

The main Aligned contracts such as the Aligned Service Manager or the Batcher Payment Service are easily accessible from the Explorer with links to etherscan.

![Figure 1: Explorer Landing Page](/files/KONCddBTfgn3JXpNYQIN)

From here, we can search for a specific batch by its Merkle Root or even find a batch, or if you want to find which batch contains a specific proof, you can also search by proof hash. We can also directly jump to any one of the last 5 submitted batches, and we can easily go to the `Batches` page, where we can navigate through the various pages of batches of proofs submitted to aligned, ordered by latest submission, and easily check their on-chain status, timestamp, and block number.

![Figure 2: Explorer Batches Page](/files/ljvaPjCVdPDtu8Qt496W)

We can also click any individual batch hash to view its details.

From the details view, we can visualize:

* The `Batch Hash` Merkle Root and a copy to clipboard button
* The batch's `Status`, either `Pending` or `Verified`
* `Batcher Sender Address` which is the address of the batcher that submitted the batch
* `Number of Proofs in this Batch`, the number of proofs included in the batch
* `Fee per Proof`, fee paid per proof in the batch in ETH and USD
* `Proofs in the Batch`, which when pressed will show a list of all the proof hashes included in the batch
* Ethereum's `Submission Block Number`, linked to etherscan
* `Submission Transaction Hash`, linked to etherscan
* `Submission Timestamp` of the batch
* Ethereum's `Response Block Number`, linked to etherscan
* `Response Transaction Hash`, linked to etherscan
* `Response Timestamp` of the batch
* Lastly, if the batch is `Verified`, we can see a small X Post button that lets us easily share on X that the batch has been verified.

![Figure 3: Explorer Batch Details Page](/files/7qpQtWEACzXn65AqyNSZ)

The `Operators` page shows a list of all registered operators, their restake concentration in %, the total amount of ETH they have restaked and their status.

These are ordered by the amount of ETH restaked, with the top operator being the one with the most ETH restaked.

When hovering over an operator, we can see the operator's address and id.

![Figure 4: Explorer Operators Page](/files/fFrgjhNxGU66i1RdB1vr)

The `Operator Details` page shows the operator's id, address, total ETH restaked, restake concentration in %, and the assets restaked order by the amount of ETH restaked.

The Operators image is also displayed, and we access other information the operator chose to share, such as their website, X, and EigenLayer dashboard profile for more details.

![Figure 5: Explorer Operator Detail Page](/files/C6JZjSHv5VuUhNYgDQVY)

The `Restake` page can be accessed by clicking the `Total Restaked` call-to-action button on either the landing page or the operators' page.

Here we can see the various assets that can be restaked, and the amount of ETH restaked in each asset.

The table is ordered by the amount of ETH restaked, with the top asset being the one with the most ETH restaked.

![Figure 6: Explorer Restake Page](/files/RypdpnyhSAJdsHwofmGx)

The `Restake Details` page shows the asset's name, symbol, total ETH restaked, Strategy Address and Token Address both linked to etherscan.

![Figure 7: Explorer Restake Detail Page](/files/exeLvx9slMxVkjy2n6En)


# Proof Aggregation Service

Aligned's Proof Aggregation Service introduces a scalable solution: compressing multiple proofs into one using recursion, drastically reducing verification costs while maintaining Ethereum-level security. This is our second major product, following the Proof Verification Layer, and is designed to give developers flexible, cost-efficient infrastructure for proving systems.

The Proof Aggregation Service is a standalone service, independent from the Proof Verification Layer. Developers submit their ZK proofs directly to the Aggregation Service, where they are aggregated in a single recursive proof that attests to the validity of all the proofs. This final proof is then submitted and verified on Ethereum. By aggregating many proofs into one, the cost of on-chain verification is amortized across the batch—developers effectively pay a fraction of the full price, plus a small aggregation fee.

![Figure 1: Proof Aggregation Service](/files/CApAUN9dqCdnGCzuUNaS)

The system is powered by recursive proving. In simple terms, the aggregation process proves that the verification of multiple proofs was correctly executed. This meta-proof is cryptographically valid and can be verified on Ethereum just like any standard ZK proof.


# Deep Dive

## Architecture Overview

The Proof Aggregation Service consists of three main components that work together to aggregate user proofs and submit them on-chain.

```
┌──────┐    ┌───────────────────────────────┐    ┌─────────────┐
│      │ 1  │ AggregationModePaymentService │ 2  │   Payments  │
│      │--->│           (Contract)          │--->│    Poller   │
│      │    └───────────────────────────────┘    └─────┬───────┘
│      │                                               │
│      │                                             3 │
│      │                                               v
│      │    ┌───────────────┐  5                ┌──────────────┐    ┌───────────────────────────────┐
│ User │ 4  │    Gateway    │------------------>│  PostgreSQL  │    │ AlignedProofAggregationService│
│      │--->│               │                   │      DB      │    │           (Contract)          │
│      │    └───────────────┘                   └──────────────┘    └───────────────────────────────┘
│      │                                               ^                          ^
│      │                                             6 │                          │
│      │                                               │                        7 │
│      │                                        ┌─────────────┐                   │
│      │                                        │    Proof    │-------------------┘
│      │                                        │  Aggregator │
└──────┘                                        └─────────────┘
```

1. User deposits ETH into `AggregationModePaymentService` contract to get quota.
2. `Payments Poller` monitors the contract for deposit events.
3. `Payments Poller` updates user quotas in the database.
4. User submits proofs to the `Gateway`.
5. `Gateway` validates and stores proofs in the database.
6. `Proof Aggregator` fetches pending proofs from the database.
7. `Proof Aggregator` aggregates proofs in the zkVM and submits to `AlignedProofAggregationService` contract.

## Supported Proof Types

The aggregation service currently supports:

* **SP1**: Aggregates proofs of type `Compressed`

## Proof Commitment

The **proof commitment** is a hash that uniquely identifies a proof. It is defined as the keccak of the proof public inputs + program ID:

* **For SP1**: The commitment is computed as: `keccak(proof_public_inputs_bytes || vk_hash_bytes)`

## Multilayer Aggregation

To scale aggregation without exhausting zkVM memory, aggregation is split into two programs:

```
                        User Proofs (n per chunk)
                                  │
          ┌───────────────────────┼───────────────────────┐
          │                       │                       │
          ▼                       ▼                       ▼
   ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
   │   Chunk 1   │         │   Chunk 2   │         │   Chunk N   │
   │  Aggregator │         │  Aggregator │         │  Aggregator │
   └──────┬──────┘         └──────┬──────┘         └──────┬──────┘
          │                       │                       │
          │    Aggregated Proofs + Merkle Roots           │
          │                       │                       │
          └───────────────────────┼───────────────────────┘
                                  │
                                  ▼
                        ┌─────────────────┐
                        │     Chunk       │
                        │   Aggregator    │
                        └────────┬────────┘
                                 │
                                 ▼
                        ┌─────────────────┐
                        │  Final Proof +  │
                        │   Merkle Root   │
                        └─────────────────┘
```

1. **User Proof Aggregator** Processes chunks of `n` user proofs. Each run creates an aggregated proof that commits to a Merkle root of the user proofs inputs. This step is repeated for as many chunks as needed. Usually each chunk contains `256` proofs but it can be lowered based on the machine specs.
2. **Chunk Aggregator** Aggregates all chunk-level proofs into a single final proof. It receives:

   * The chunked proofs
   * The original [proofs commitments](#proof-commitment) included in each chunk received

   During verification, it checks that each chunk's committed Merkle root matches the reconstructed root to ensure input correctness. The final Merkle root, representing all user [proofs commitments](#proof-commitment), is then committed as a public input.

## Verification

Once aggregated, the proof is sent to Ethereum and verified via the `AlignedProofAggregationService` contract. The contract invokes `verifySP1` which receives:

* The public inputs
* The proof binary

The program ID is hardcoded in the contract to ensure only trusted aggregation programs (`chunk_aggregator`) are accepted.

If verification succeeds, the new proof is added to the `aggregatedProofs` map in contract storage.

### Proof Inclusion Verification

To verify a user's proof on-chain, the following must be provided:

* The proof bytes
* The proof public inputs
* The program ID (vk hash)
* A Merkle proof

The Merkle root is computed and checked for existence in the contract using the `verifyProofInclusion` function of the `AlignedProofAggregationService` contract, which:

1. Computes the merkle root
2. Returns `true` or `false` depending on whether there exists an `aggregatedProof` with the computed root.

## Data Availability

When submitting the aggregated proof to Ethereum, we include a **blob** that contains the [commitments](#proof-commitment) of all the individual proofs that were aggregated. This blob serves two main purposes:

* It makes the [proof commitments](#proof-commitment) publicly available for **18 days**.
* It allows users to:
  * Inspect which proofs were aggregated
  * Get a Merkle proof to verify that their proof is included in the aggregated proof


# Rollup-as-a-Service Platform

Aligned's RaaS platform integrates RISC-V zkVMs, the new [Ethrex execution client](https://github.com/lambdaclass/ethrex), and our ZK Verification Layer to offer fast, reliable, and secure one-click ZK-rollup deployment — including full support for based rollups — making it as simple as launching a Web2 service.

Our RaaS platform will be integrated with our upcoming products to give developers all the tools they need to operate a complete ecosystem: wallet-as-a-service infrastructure for simplified onboarding, meta-proving services that give users access to provers provided by Aligned or other third-party centralized or decentralized proving services, and our interoperability protocol for efficient cross-chain liquidity access.

![Figure 1: Aligned Suite of Products](/files/9GzihUKLN6yp37iSWbyW)

## What advantages will Aligned's RaaS platform offer for your project?

Aligned's RaaS platform will offer significant benefits, starting with substantial time and cost savings, enabling teams to deploy rollups faster and more affordably. This accessibility unlocks new use cases that would otherwise be economically unfeasible. A key advantage is customizability and modularity. Our platform will enable easy mixing and matching of different rollup components, helping build the ideal solution for specific needs. From initial deployment to long-term maintenance, we handle upgrades, performance optimization, and assist you in integrating new capabilities as they emerge.

## Why is Aligned using Ethrex for Based ZK-rollups?

Aligned chose Ethrex as the rollup stack for our RaaS platform due to its stable, minimalist, and modular design and its support for the latest features like based rollups. This aligns with our commitment to reliability and performance, and ensures that we can continue to offer our users the best technology to access Ethereum.

Ethrex operates in two modes:

* Ethrex L1: a streamlined Ethereum execution client
* Ethrex L2: a ZK-rollup client supporting multiple proving systems (RISC-V zkVMs like SP1 or R0VM, and Trusted Execution Environments (TEEs))

Ethrex's design principles emphasize minimalism, clarity, and simplicity, resulting in a codebase that is both fast and resilient. This approach enables rapid iteration and the early adoption of next-generation features, which is crucial for staying ahead in the rapidly evolving blockchain landscape. Additionally, Ethrex's vertical integration and minimal dependencies ensure efficient operation and ease of maintenance, enabling low overhead and providing a robust foundation for our services.

By leveraging Ethrex, Aligned can offer a streamlined, high-performance RaaS platform that simplifies the deployment of Layer 2 chains, empowering developers to build scalable applications with greater efficiency and control.

## What are Based rollups?

Based rollups are rollups that use Ethereum L1 proposers and builders for sequencing (ordering its transactions and forming blocks), as opposed to a separate (typically centralized) sequencer.

Based sequencing is “based on the L1”, meaning that rollups using this design give Ethereum’s validators the power to sequence rollup transactions. This simplifies what a rollup needs to do and lets it take advantage of the extensive, battle-tested infrastructure that makes up Ethereum’s block building market. The result is a rollup architecture that offers greater feature parity with the L1 and many other benefits that are important to customers looking to launch their own rollup.

## The benefits of Based Rollups

Based rollups provide a range of benefits that address many of the shortcomings rollups currently face. Because non-based rollups are not synchronously composable with Ethereum their proliferation has resulted in liquidity fragmentation and the majority of DeFi volume taking place on the L1, which has higher fees. Based rollups enable atomic synchronous composability and full access to Ethereum’s liquidity, ultimately resulting in improved interoperability between apps and smart contracts and greatly improved UX.

By eliminating the need for a dedicated sequencer, based rollups are inherently more decentralized, have stronger liveness guarantees, are more censorship-resistant, and more credibly neutral than non-based rollups. These are core features of Ethereum that make it the best decentralized smart contract platform for high-value, global transactions—features which non-based rollups fail to replicate.

Based rollups benefit from reduced operating costs as they don’t require operators to run a dedicated sequencer, but also make use of the L1s existing block building pipeline. This means based rollups do not need to attract sophisticated actors to provide these services, further reducing costs and improving efficiency.

## How do ZK-rollups use Aligned’s ZK Verification Layer?

A simplified version of this process can be found in Figure 2. Proofs for batches of rollup transactions (blocks) are sent to Aligned’s ZK Verification Layer (the Proof Aggregation Service, used with or without the Proof Verification Layer), which converts them into one proof that is verified on Aligned's L1 contract.

![Figure 2: ZK-rollups and the role of Aligned](https://github.com/yetanotherco/aligned_layer/blob/testnet/docs/images/zkrollups_and_the_role_of_aligned.png)


# Submitting proofs

Make sure you have Aligned installed as specified [here](/introduction/1_try_aligned#quickstart).

If you run the examples below, make sure you are in Aligned's repository root.

You can check your submitted proofs on [Mainnet Explorer](https://explorer.alignedlayer.com), [Sepolia Explorer](https://sepolia.explorer.alignedlayer.com), and [Hoodi Explorer](https://hoodi.explorer.alignedlayer.com).

## Supported Verifiers

The following is the list of the verifiers currently supported by Aligned:

* :white\_check\_mark: gnark - Groth16 (with BN254) [(v0.12.0)](https://github.com/Consensys/gnark/releases/tag/v0.12.0)
* :white\_check\_mark: gnark - Plonk (with BN254 and BLS12-381) [(v0.12.0)](https://github.com/Consensys/gnark/releases/tag/v0.12.0)
* :white\_check\_mark: SP1 [(v5.0.0)](https://github.com/succinctlabs/sp1/releases/tag/v5.0.0)
* :white\_check\_mark: Risc0 [(v3.0.3)](https://github.com/risc0/risc0/releases/tag/v3.0.3). Previous versions are also compatible.
* :white\_check\_mark: Circom [(v2.2.2)](https://github.com/iden3/circom/releases/tag/v2.2.2)
* :white\_check\_mark: Mina (Testnet only - Sepolia, Hoodi)
* :white\_check\_mark: Mina Account (Testnet only - Sepolia, Hoodi)

Learn more about future verifiers [here](/architecture/0_supported_verifiers).

## 1. Import/Create Keystore file

If you already have a keystore file, you can ignore this section and start sending proofs. We give two examples of how to generate one. The first one using Foundry, and the second one using EigenLayer CLI

### Alternative 1: With foundry

You need to have installed [Foundry](https://book.getfoundry.sh/getting-started/installation).

{% hint style="warning" %}
When creating a new wallet keystore and private key please use strong passwords for your own protection.
{% endhint %}

* If you are creating a new account, create a private key with:

  ```bash
  cast wallet new-mnemonic --words 12
  ```

  It will show you a new mnemonic phrase and a public-private key pair, similar to the following example:

  ```
  Phrase:
  test test test test test test test test test test test test

  Accounts:
  - Account 0:
  Address:     0xabcd...1234
  Private key: 0x1234...abcd
  ```
* Import the wallet using the private key previously generated, or whichever you want to use, and write a password to use it.

  ```bash
  mkdir -p ~/.aligned_keystore/
  cast wallet import ~/.aligned_keystore/keystore0 --interactive
  ```

  You have to paste your private key and set a password for the keystore file.

This will create the ECDSA keystore file in `~/.aligned_keystore/keystore0`

### Alternative 2: With EigenLayer CLI

* If you have the EigenLayer CLI installed, the keystore can be generated following [these](https://docs.eigencloud.xyz/products/eigenlayer/operators/howto/operator-installation) instructions. The key will be stored into `~/.eigenlayer/operator_keys`.

## 2. Send funds to Aligned

To send proofs to Aligned using the Batcher, the user must first deposit some funds in Aligned to pay for the verification of his proofs.

To use it, you can use the `aligned` CLI, as shown with the following example:

```bash
aligned deposit-to-batcher \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--network hoodi \
--keystore_path <keystore_path> \
--amount 0.1ether
```

This command allows the usage of the following flags:

* `--rpc_url` to specify the rpc url to be used.
* `--network` to specify the network to be used. Can be `devnet`, `sepolia`, `mainnet`, or `hoodi`.
* `--keystore_path` the path to the keystore.
* `--amount` the number of ethers to transfer to the Batcher.
* Note: `--amount` flag parameter must be with the shown format, `XX.XXether`.

After depositing funds, you can verify the Service has correctly received them by executing the following command:

```bash
aligned get-user-balance \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--network hoodi \
--user_addr <user_addr>
```

These commands allow the usage of the following flags:

* `--rpc_url` to specify the rpc url to be used.
* `--network` to specify the network to be used. Can be `devnet`, `sepolia`, `mainnet`, or `hoodi`.
* `--user_addr` the address of the user that funded the Batcher.

## 3. Submit your proof to the batcher

This guide will focus on how to submit proofs using the Aligned CLI. To integrate the proof submission process into your application, check the [First Aligned Application tutorial](/guides/2_build_your_first_aligned_application) where we explain how to generate and submit a proof using the Aligned SDK.

Proof submission is done via the `submit` command of the Aligned CLI. The arguments for the submit command are:

* `proving_system`: The proving system corresponding to the proof you want to submit.
* `proof`: The path of the proof associated to the computation to be verified.
* `vm_program`: When the proving system involves the execution of a program in a zkVM, this argument is associated with the compiled program or some other identifier of the program.
* `pub_input`: The path to the file with the public input associated with the proof.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`
* `rpc_url`: The RPC Ethereum node URL.
* `proof_generator_addr`: An optional parameter that can be used in some applications to avoid front-running.
* `batch_inclusion_data_directory_path`: An optional parameter indicating the directory where to store the batcher response data. If not provided, the folder with the responses will be created in the current directory.

### SP1 proof

The current SP1 version used in Aligned is `v5.0.0`.

The SP1 proof needs the proof file and the vm program file.

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system SP1 \
--proof <proof_file> \
--vm_program <vm_program_file> \
--public_input <pub_input_file> \
--proof_generator_addr [proof_generator_addr] \
--batch_inclusion_data_directory_path [batch_inclusion_data_directory_path] \
--keystore_path <path_to_ecdsa_keystore> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

**Example**

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system SP1 \
--proof ./scripts/test_files/sp1/sp1_fibonacci_5_0_0.proof \
--vm_program ./scripts/test_files/sp1/sp1_fibonacci_5_0_0.elf \
--public_input ./scripts/test_files/sp1/sp1_fibonacci_5_0_0.pub \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

### Risc0 proof

The current Risc0 version used in Aligned is `v3.0.3`.

The Risc0 proof needs the proof file and the vm program file (vm program file is the image id).

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system Risc0 \
--proof <proof_file> \
--vm_program <vm_program_file> \
--public_input <pub_input_file> \
--proof_generator_addr [proof_generator_addr] \
--batch_inclusion_data_directory_path [batch_inclusion_data_directory_path] \
--keystore_path <path_to_ecdsa_keystore> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

**NOTE**: As said above, Aligned currently supports Risc0 proofs from `risc0-zkvm` version `v3.0.3`. For generating proofs using `cargo risc-zero` please ensure you are using `v3.0.3` or your proof will not be verified.

If you can't install `cargo-risczero` `v3.0.3`, you can manually modify your `cargo.toml` on the host project to point to `v3.0.3`:

```toml
risc0-zkvm = { git = "https://github.com/risc0/risc0", tag = "v3.0.3", default-features = false, features = [
    "prove",
] }
```

* Note: In Risc0 verification `--pub_input` contains the bytes of the `receipt.journal.bytes` which contains both the public input (`env::read()`) and public output (`env::commit()`) values of a program executed in the Risc0 VM. If your Risc0 program contains public outputs, but no public inputs you still need to submit the serialized `receipt.journal.bytes` with your proof using the Aligned CLI for your proof to be verified.

**Example**

```bash
rm -rf ~/.aligned/aligned_verification_data/ &&
aligned submit \
--proving_system Risc0 \
--proof ./scripts/test_files/risc_zero/fibonacci_proof_generator/risc_zero_fibonacci_3_0_3.proof \
--vm_program ./scripts/test_files/risc_zero/fibonacci_proof_generator/fibonacci_id_3_0_3.bin \
--public_input ./scripts/test_files/risc_zero/fibonacci_proof_generator/risc_zero_fibonacci_3_0_3.pub \
--aligned_verification_data_path ~/.aligned/aligned_verification_data \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

### GnarkPlonkBn254, GnarkPlonkBls12\_381 and GnarkGroth16Bn254

The GnarkPlonkBn254, GnarkPlonkBls12\_381 and GnarkGroth16Bn254 proofs need the proof file, the public input file and the verification key file.

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system <GnarkPlonkBn254|GnarkPlonkBls12_381|GnarkGroth16Bn254> \
--proof <proof_file> \
--public_input <public_input_file> \
--vk <verification_key_file> \
--proof_generator_addr [proof_generator_addr] \
--batch_inclusion_data_directory_path [batch_inclusion_data_directory_path] \
--keystore_path <path_to_ecdsa_keystore> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

**Examples**:

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system GnarkPlonkBn254 \
--proof ./scripts/test_files/gnark_plonk_bn254_script/gnark_plonk_0_12_0.proof \
--public_input ./scripts/test_files/gnark_plonk_bn254_script/gnark_plonk_pub_input_0_12_0.pub \
--vk ./scripts/test_files/gnark_plonk_bn254_script/gnark_plonk_0_12_0.vk \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system GnarkPlonkBls12_381 \
--proof ./scripts/test_files/gnark_plonk_bls12_381_script/gnark_plonk_0_12_0.proof \
--public_input ./scripts/test_files/gnark_plonk_bls12_381_script/gnark_plonk_pub_input_0_12_0.pub \
--vk ./scripts/test_files/gnark_plonk_bls12_381_script/gnark_plonk_0_12_0.vk \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system GnarkGroth16Bn254 \
--proof ./scripts/test_files/gnark_groth16_bn254_script/gnark_groth16_0_12_0.proof \
--public_input ./scripts/test_files/gnark_groth16_bn254_script/gnark_groth16_0_12_0.pub \
--vk ./scripts/test_files/gnark_groth16_bn254_script/gnark_groth16_0_12_0.vk \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

### CircomGroth16Bn256

The CircomGroth16Bn256 proof needs the proof file, the public input file and the verification key file.

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system CircomGroth16Bn256 \
--proof <proof_file> \
--public_input <public_input_file> \
--vk <verification_key_file> \
--proof_generator_addr [proof_generator_addr] \
--batch_inclusion_data_directory_path [batch_inclusion_data_directory_path] \
--keystore_path <path_to_ecdsa_keystore> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

**Example**

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system CircomGroth16Bn256 \
--proof ./scripts/test_files/circom_groth16_bn256_script/proof.json \
--public_input ./scripts/test_files/circom_groth16_bn256_script/public.json \
--vk ./scripts/test_files/circom_groth16_bn256_script/verification_key.json \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

### Mina proof

{% hint style="warning" %}
Mina proofs are only available on testnets (Sepolia, Hoodi). To use this verifier, you need to checkout to the `staging` branch:

```bash
git checkout staging
```

{% endhint %}

The Mina proof needs the proof file and the public input file.

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system Mina \
--proof <proof_file> \
--public_input <public_input_file> \
--proof_generator_addr [proof_generator_addr] \
--batch_inclusion_data_directory_path [batch_inclusion_data_directory_path] \
--keystore_path <path_to_ecdsa_keystore> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

**Example**

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system Mina \
--proof ./scripts/test_files/mina/devnet_mina_state.proof \
--public_input ./scripts/test_files/mina/devnet_mina_state.pub \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

### MinaAccount proof

{% hint style="warning" %}
MinaAccount proofs are only available on testnets (Sepolia, Hoodi). To use this verifier, you need to checkout to the `staging` branch:

```bash
git checkout staging
```

{% endhint %}

The MinaAccount proof needs the proof file and the public input file.

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system MinaAccount \
--proof <proof_file> \
--public_input <public_input_file> \
--proof_generator_addr [proof_generator_addr] \
--batch_inclusion_data_directory_path [batch_inclusion_data_directory_path] \
--keystore_path <path_to_ecdsa_keystore> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

**Example**

```bash
rm -rf ./aligned_verification_data/ &&
aligned submit \
--proving_system MinaAccount \
--proof ./scripts/test_files/mina_account/mina_account.proof \
--public_input ./scripts/test_files/mina_account/mina_account.pub \
--keystore_path ~/.aligned_keystore/keystore0 \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```


# Build your first Aligned Application

In this guide you will learn how to build applications on top of Aligned. It provides a few simple steps to help you verify ZK proofs generated within your system.

First we will show you an example of a trivia application, called ZkQuiz. We'll show you the different components and how they interact with each other to be able to submit the proof to aligned and verify that was correctly included in a batch.

## ZkQuiz

ZkQuiz is an application that leverages Aligned's ZK verification infrastructure to run a small trivia. The proof allows any party to check that the quiz was answered right or wrong. If answered correctly, the user receives an NFT.

{% hint style="warning" %}
Received NFTs from ZkQuiz do not have any value. It is just a test application
{% endhint %}

The process is as follows:

1. The user runs ZKQuiz and answers the questions.
2. ZKQuiz generates a ZK Proof of correct answers.
3. The proof is posted on Aligned.
4. Upon verification, ZKQuiz mints an NFT via a Smart Contract.

The NFT is only granted if the user's answers correctly. Incorrect answers or tampering with the ZKQuiz code will result in proof generation failure or mismatched checksums, preventing NFT minting.

Next, we will see how to execute ZKQuiz to get your own ZKQuiz NFT!

### Requirements

1. [Rust v1.80.0](https://www.rust-lang.org/tools/install)
2. [Foundry](https://getfoundry.sh)

{% hint style="info" %}
ELF commitment was generated with Rust v1.80.1 and SP1 v4.1.7.
{% endhint %}

### Usage

#### 1. Clone the repository

```bash
git clone https://github.com/yetanotherco/aligned_layer.git && cd aligned_layer
```

#### 2. Create a Keystore

You need a keystore to pay for the proof verification, you can use cast to create a local keystore. If you already have one, you can skip this step.

```bash
cast wallet new-mnemonic
```

Then you can import your created keystore using:

```bash
cast wallet import --interactive <keystore_name>
```

The keystores are saved in `~/.foundry/keystores`. You can find more information about keystores in the [cast documentation](https://book.getfoundry.sh/reference/cast/wallet-commands).

Then you need to get some funds to pay for gas and proof verification. You can do this by using the [Google Faucet](https://cloud.google.com/application/web3/faucet/ethereum/hoodi).

#### 3. Answer Quiz

To answer quiz questions run:

```bash
cd examples/zkquiz
make answer_quiz KEYSTORE_PATH=<path_to_keystore>
```

This will:

1. Ask quiz questions
2. Generate ZK proof
3. Pay & submit proof to aligned for verification
4. Wait for proof to be verified in aligned
5. Claim NFT if proof is verified

## Deep dive

The ZkQuiz source code is available [here](https://github.com/yetanotherco/aligned_layer/blob/testnet/examples/zkquiz/README.md).

ZkQuiz has three main components:

* App/script
* Program
* Verifier contract

The user interacts with ZkQuiz App to solve a trivia challenge answering questions. Then, the App generates a Zk Proof with the Program generated using SP1.

{% hint style="info" %}
The ZkQuiz Program is built using SP1 following the [quickstart guide](https://docs.succinct.xyz/docs/sp1/getting-started/quickstart). For your projects, you can user any of the [prooving systems supported by Aligned](/architecture/0_supported_verifiers).
{% endhint %}

Once the proof is generated, the App sends the proof to Aligned, and once it is verified, the App calls to the ZkQuiz Verifier Contract to check the proof verification and send an NFT to the user is the proof was verified in Aligned.

![ZkQuiz](/files/syeGFpixv835ypWALChx)

Now, lets build ZkQuiz from scratch.

### Program

First you need to write the code you want to prove; in this case it looks like this:

```rust
// program/src/main.rs

#![no_main]

use tiny_keccak::{Hasher, Sha3};
sp1_zkvm::entrypoint!(main);

pub fn main() {
    let answers = sp1_zkvm::io::read::<String>();
    let mut sha3 = Sha3::v256();
    let mut output = [0u8; 32];

    sha3.update(answers.as_bytes());

    sha3.finalize(&mut output);

    if output
        != [
            232, 202, 155, 157, 82, 242, 126, 73, 75, 22, 197, 34, 41, 170, 163, 190, 22, 29, 192,
            5, 99, 134, 186, 25, 77, 128, 188, 154, 238, 70, 245, 229,
        ]
    {
        panic!("Answers do not match");
    }
}
```

The program takes the user answers as inputs and checks that the hash of the inputs matches with the expected output. This is the program that will be compiled generating a binary file that will be ran by the zkVm and used later in the application side. In our case this file is already generated and is located on `/quiz/program/elf/riscv32im-succinct-zkvm-elf`.

### Verifier Contract

To check if a proof was verified in Aligned, you can create your own smart contract in order to make a call to the `AlignedServiceManager` contract.

ZkQuiz uses a Smart Contract to check if aligned verified the proof and gives an NFT to the user.

{% hint style="info" %}
It is not mandatory to create an Smart Contract. You can make off-chain apps that interact with the Aligned contract directly.
{% endhint %}

**Program Identifier Validation**

The contract first checks that the commitment of the program matches with the one that we expect. In our zkquiz example, we get the following elf commitment:

```solidity
// contracts/src/VerifierContract.sol
bytes32 public elfCommitment = 0x3f99615fdf3b67a01e41b38eee75a32c778ee2fa631bd74e01c89afc2f70f5de;
```

You can generate the expected commitment without actually generating and submitting a proof using the Aligned CLI tool running:

```bash
aligned get-vk-commitment --verification_key_file <path_to_input_file> --proving_system <proving_system_id>
```

where the `path_to_input_file` is the path to the `elf` file generated with the program compilation and the `proving_system_id` the name of the proving system used for compilation, in this case `SP1`.

Then, the contract validates if the provided commitment of the program identifier matches the expected one.

```solidity
// contracts/src/VerifierContract.sol
if (elfCommitment != provingSystemAuxDataCommitment) {
    revert InvalidElf(provingSystemAuxDataCommitment);
}
```

The contract makes a call to the `AlignedServiceManager` contract to check if the proof was verified in Aligned.

```solidity
// contracts/src/VerifierContract.sol
(
   bool callWasSuccessfull,
   bytes memory proofIsIncluded
) = alignedServiceManager.staticcall(
                abi.encodeWithSignature(
                    "verifyBatchInclusion(bytes32,bytes32,bytes32,bytes20,bytes32,bytes,uint256,address)",
                    proofCommitment,
                    pubInputCommitment,
                    provingSystemAuxDataCommitment,
                    proofGeneratorAddr,
                    batchMerkleRoot,
                    merkleProof,
                    verificationDataBatchIndex,
                    paymentServiceAddr
                )
            );

require(callWasSuccessfull, "static_call failed");

bool proofIsIncludedBool = abi.decode(proofIsIncluded, (bool));

require(proofIsIncludedBool, "proof not included in batch");
```

Finally, if the proof was verified, the contract sends a NFT to the user

```solidity
// contracts/src/VerifierContract.sol

    _mint(msg.sender, tokenId);
    _setTokenURI(
        tokenId,
        "ipfs://QmUKviny9x2oQUegyJFFBAUU2q5rvu5CsPzrUaBSDukpHQ"
    );
```

### App

The first part of the app takes the answers of the user via CLI. Once the user answer the questions, we prepare them and initiate the prover, as follows:

```rust
// script/src/main.rs

// Include the bytes of the compiled program.
const ELF: &[u8] = include_bytes!("../../program/elf/riscv32im-succinct-zkvm-elf");

// Generate proof.
let mut stdin = SP1Stdin::new();

stdin.write(&user_awnsers);

println!("Generating Proof ");

let client = ProverClient::new();
let (pk, vk) = client.setup(ELF);

let Ok(proof) = client.prove(&pk, stdin).compressed().run() else {
    println!("Incorrect answers!");
    return;
};

println!("Proof generated successfully. Verifying proof...");
client.verify(&proof, &vk).expect("verification failed");
println!("Proof verified successfully.");
```

Now we can send the generated proof to Aligned using the SDK.

```rust
// script/src/main.rs

// Serialize the proof to later save in a file.
let proof = bincode::serialize(&proof).expect("Failed to serialize proof");

// Preparing the data needed for verification in Aligned
let verification_data = VerificationData {
    proving_system: ProvingSystemId::SP1,
    proof,
    proof_generator_addr: wallet.address(),
    vm_program_code: Some(ELF.to_vec()),
    verification_key: None,
    pub_input: None,
};

let max_fee = estimate_fee(&rpc_url, PriceEstimate::Default)
    .await
    .expect("failed to fetch gas price from the blockchain");

let max_fee_string = ethers::utils::format_units(max_fee, 18).unwrap();

let nonce = get_nonce_from_ethereum(&rpc_url, wallet.address(), NETWORK)
    .await
    .expect("Failed to get next nonce");

// Submit to Aligned.
let aligned_verification_data = submit_and_wait_verification(
    &rpc_url,
    NETWORK,
    &verification_data,
    max_fee,
    wallet.clone(),
    nonce,
    )
.await
.unwrap();
```

Finally, if the proof was sent to Aligned correctly, we can interact with our verifier Smart Contract to verify that the proof was correctly posted in aligned and claim the NFT.

```rust
// script/src/main.rs

// Sends a transaction to the verifier contract with the
// verification data provided by aligned
claim_nft_with_verified_proof(
    &aligned_verification_data,
    signer,
    &args.verifier_contract_address,
)
.await
.expect("Claiming of NFT failed ...");
```

You can find the full code of the proof submission and verification in the [ZKQuiz App](https://github.com/yetanotherco/aligned_layer/blob/testnet/examples/zkquiz/quiz/script/src/main.rs).


# Modify ZkQuiz Questions

In [Build your first Aligned Application](/guides/2_build_your_first_aligned_application), we show how to build a trivia application, called ZkQuiz. ZKQuiz asks the user three questions, and if answered correctly, generates a ZK Proof of the correct answers, posts the proof on Aligned, and upon verification, mints an NFT via a smart contract.

In this guide, we will show you how to replace those questions with your own custom ones.

{% hint style="warning" %}
This guide assumes you have already read [Build your first Aligned Application](/guides/2_build_your_first_aligned_application)
{% endhint %}

## 1. Modify the Questions Asked

First, we need to modify the questions presented to the user. To do this, navigate to our example in `examples/zkquiz/quiz/script/src/main.rs` and change the questions as needed. Here’s a new set of questions with their respective answers:

```rust
let mut user_answers = "".to_string();

let question1 = "What is the capital of France?";
let answers1 = ["Berlin", "Paris", "Madrid"];
user_answers.push(ask_question(question1, &answers1));

let question2 = "What is the chemical symbol for gold?";
let answers2 = ["Au", "Ag", "Fe"];
user_answers.push(ask_question(question2, &answers2));

let question3 = "What is the native cryptocurrency of Ethereum?";
let answers3 = ["Bitcoin", "Ether", "Litecoin"];
user_answers.push(ask_question(question3, &answers3));
```

## 2. Update the Program

Next, we need to update the program to be proven with the new correct answers. As described in [Build your first Aligned Application](/guides/2_build_your_first_aligned_application), the program in `examples/zkquiz/quiz/program/src/main.rs` takes the user answers as inputs and checks that the SHA3-256 hash of these inputs matches the expected output. Therefore, we need to update the expected output with the hash of our new correct answers.

If we concatenate the correct answers to the questions above, we get `bab`, so we need to calculate the SHA3-256 hash of that:

```
SHA3-256(bab)
```

You can use any SHA3-256 Rust library or even online tools for this purpose. Here we provide a python script that calculates it for you:

```python
import hashlib

correct_answers = "bab"

# Calculate SHA3-256 hash
hash_object = hashlib.sha3_256(correct_answers.encode())

# Get the hash as a list of integers (byte values)
hash_bytes = list(hash_object.digest())

print(hash_bytes)
```

After executing the script, we get:

```python
[216, 11, 193, 177, 136, 178, 254, 150, 59, 128, 97, 103, 97, 128, 55, 57, 22, 242, 26, 1, 186, 223, 215, 118, 206, 47, 12, 206, 114, 118, 220, 93]
```

Now we can update it in `examples/zkquiz/quiz/program/src/main.rs` as follows:

```rust
if output
        != [
            216, 11, 193, 177, 136, 178, 254, 150, 59, 128, 97, 103, 97, 128, 55, 57, 22, 242, 26,
            1, 186, 223, 215, 118, 206, 47, 12, 206, 114, 118, 220, 93,
        ]
    {
        panic!("Answers do not match");
    }
```

## 3. Compile the Program

Now we need to compile the updated Program, generating the binary file that will be run by the zkVM (ELF). For this, ensure that the [SP1 Rust toolchain](https://docs.succinct.xyz/docs/sp1/introduction) is installed. Run:

```
make compile_elf
```

which will output the compiled ELF to the file program/elf/riscv32im-succinct-zkvm-elf.

## 4. Run the new ZkQuiz

We are ready to run our new version of ZkQuiz.

To do this, follow the same instructions as in the original [Build your first Aligned Application](/guides/2_build_your_first_aligned_application)


# Validating public input

In some applications, it is crucial to ensure that a third party has performed a computation correctly and to make use of the result of that computation. To achieve this, the third party must interact with Aligned, using the Aligned SDK, to obtain the `AlignedVerificationData`, a receipt indicating that the proof of the computation was verified correctly. The application should then receive both the `AlignedVerificationData` and the result of the computation. After confirming that the proof was verified by Aligned, it must check that the posted result matches the one committed in the `AlignedVerificationData`.

This guide demonstrates how to validate Risc0 and SP1 proofs using the Aligned SDK. The program in this example is a Fibonacci sequence calculator. It generates a public input that corresponds to the number of fibonacci being calculated and the last two Fibonacci numbers of the sequence, taken modulo 7919. Our goal is to validate, within a smart contract, that the public input commitments match these numbers.

In this case, the Fibonacci number to be calculated is **500** and the last two numbers of the sequence modulo 7919 are **1268** and **1926**.

## Requirements

* [SP1](https://docs.succinct.xyz/docs/sp1/getting-started/install)
* [Risc0](https://dev.risczero.com/api/zkvm/install)
* [Foundry](https://book.getfoundry.sh/getting-started/installation)

## The program

The Fibonacci program to be proven is essentially a Rust program with a few additional functions from the `risc0` and `sp1` libraries. These extra functions allow for the submission of public inputs and enable the generation of a proof.

### Risc0

For `risc0`, the Fibonacci program can be found in `examples/validating-public-input/risc_zero/fibonacci_proof_generator/methods/guest/src/main.rs`, and it's known as the guest code. This code compiles into a binary file that is later used to correctly generate the proof. The host code, located in `examples/validating-public-input/risc_zero/fibonacci_proof_generator/host/src/main.rs`, is responsible for executing the program with the given input and generating a receipt that contains both the proof and all output data from the process.

For more details about `risc0` and the interaction between guest and host code, as well as how the various parts work, you can refer to the official documentation [here](https://dev.risczero.com/api/zkvm/).

### SP1

For `SP1`, the Fibonacci program is located in `examples/validating-public-input/sp1/fibonacci/program/src/main.rs`, and it functions similarly to the one written for `risc0`. It follows a similar structure and process to generate a proof. The code responsible for executing and proving the program can be found in `examples/validating-public-input/sp1/fibonacci/script/src/main.rs`. Both components work in tandem, much like in the `risc0` framework.

## Generate your ZK Proof

> \[!IMPORTANT] To generate the proof ensure you have [docker](https://www.docker.com/get-started/) installed and the docker daemon running. This is necessary to ensure deterministic builds of the binary we want to generate a proof of. If not used, builds may differ depending on the system you are running on. To know more about this, check [this link](https://dev.risczero.com/terminology#deterministic-builds) from RiscZero docs or [this](https://docs.succinct.xyz/docs/sp1/writing-programs/compiling) from SP1.

To submit proofs to **Aligned** and get them verified, you first need to generate those proofs. Every proving system has its own method for generating proofs.

Examples on how to generate proofs can be found in the [generating proofs guide](/guides/4_generating_proofs).

To generate the proof required for this example, run the following commands:

* For **Risc0**: `make generate_risc0_fibonacci_proof`
* For **SP1**: `make generate_sp1_fibonacci_proof`

Once completed, you will see output that includes the program ID, the public inputs (which are the initial number of steps in the sequence and the last two Fibonacci numbers of the sequence), and the verification result, like so:

```
Program ID: 0xf000637ed63d26fc664f16666aebf05440ddb7071931240dc49d9bbcfbac304a
n: 500
a: 1268
b: 1926
Verification result: true
Fibonacci proof, pub input, and image ID generated in <verifier> folder
```

The command generates three different files, which will be used for later validation:

* An `.elf` file containing the compiled program.
* A `.proof` file containing the proof bytes for the program.
* A `.pub` file containing the serialized public input bytes committed by the program.

## Submit and verify the proof to Aligned

> For more details on submitting proofs and setting up a local wallet keystore, refer to the [submitting proofs guide](/guides/0_submitting_proofs).

The proof submission and verification process can be done either using the SDK or the Aligned CLI. In this case, we’ll use the **Aligned SDK** to better illustrate how the entire process works.

To submit the **Risc0** proof generated in this example, run:

```sh
make submit_fibonacci_risc0_proof KEYSTORE_PATH=<KEYSTORE_PATH>
```

Alternatively, you can submit the one generated with **SP1** by running:

```sh
make submit_fibonacci_sp1_proof KEYSTORE_PATH=<KEYSTORE_PATH>
```

This command will execute the Rust code that handles the proof submission with the appropriate verifier. You can find this code in the file `examples/validating-public-input/aligned-integration/src/main.rs`. It acts as the integration layer between the proof-generating program and the proof submission process to **Aligned**.

The data necessary to send to aligned follows this structure:

```rust
VerificationData {
    // The proving system ID.
    proving_system
    // The proof bytes previously serialized.
    proof,
    // The public input bytes.
    pub_input,
    // The bytes of the verification key if necessary.
    verification_key: None,
    // The bytes corresponding to the compiled program.
    vm_program_code: elf,
    // The address of the wallet that generated the proof.
    proof_generator_addr,
}
```

It could take some time but once this proof is submitted and executed within Aligned, you should see an output similar to:

```
INFO  aligned_integration: Saved batch inclusion data to ".../aligned_layer/examples/validating-public-input/aligned-integration/batch_inclusion_data/<JSON_FILE_NAME>"
```

The file logged in `<JSON_FILE_NAME>` will contain the `AlignedVerificationData`. This data is essential for sending the transaction to the `verifyBatchInclusion` method of the smart contract, which verifies the inclusion of your proof in Aligned and checks the correctness of the compiled program and public inputs.

Each generated proof gets its own file name, so ensure to save the filename or remember it for future steps, as it will be required later. You can check the generated data files in `aligned-layer/examples/validating-public-input/aligned-integration/batch_inclusion_data`

## Validating the public inputs

To check if a proof was verified in Aligned, you need to make a call to the `AlignedServiceManager` contract from within your smart contract.

We previously reviewed the structure of a Verifier contract when building our first application; you can find that information [here](/guides/2_build_your_first_aligned_application#verifier-contract) if you'd like to revisit it. Now, we need to implement a check to ensure that the public inputs match the expected values. To accomplish this, we have added a new parameter to our `verifyBatchInclusion` function in the smart contract, which will receive the bytes of the public inputs directly from the `.pub` file generated during compilation.

Now the function should look like this for both sp1 and risc0 proofs.

```solidity
function verifyBatchInclusion(
    bytes32 proofCommitment,
    bytes32 pubInputCommitment,
    bytes32 programIdCommitment,
    bytes20 proofGeneratorAddr,
    bytes32 batchMerkleRoot,
    bytes memory merkleProof,
    uint256 verificationDataBatchIndex,
    bytes memory pubInputBytes
) public returns (bool) {
    require(
        pubInputCommitment == keccak256(abi.encodePacked(pubInputBytes)),
        "Fibonacci numbers don't match with public input"
    );
```

Since the format of the generated byts is the same for both of the verifiers, we can later decode the inputs if we want to do something with them, in this case we emit an event:

```solidity
(uint32 n, uint32 fibN, uint32 fibNPlusOne) = bytesToTwoUint32(pubInputBytes);

emit FibonacciNumbers(n, fibN, fibNPlusOne);

function bytesToTwoUint32(
    bytes memory data
) public pure returns (uint32, uint32, uint32) {
    require(data.length >= 8, "Input bytes must be at least 8 bytes long");

    uint32 first = uint32(uint8(data[0])) |
        (uint32(uint8(data[1])) << 8) |
        (uint32(uint8(data[2])) << 16) |
        (uint32(uint8(data[3])) << 24);

    uint32 second = uint32(uint8(data[4])) |
        (uint32(uint8(data[5])) << 8) |
        (uint32(uint8(data[6])) << 16) |
        (uint32(uint8(data[7])) << 24);

    uint32 third = uint32(uint8(data[8])) |
        (uint32(uint8(data[9])) << 8) |
        (uint32(uint8(data[10])) << 16) |
        (uint32(uint8(data[11])) << 24);

    return (first, second, third);
}
```

We have already implemented the contract with these features; you can check it in `contracts/src/FibonacciValidator.sol`.

To test it, you'll need to deploy the contract. First, create a new `.env` file following the format of `.env.example`, ensuring to add the `private_key` you wish to use for deployment. Make sure you have a sufficient balance on the Hoodi testnet. For all other values, you can use the default settings provided in the comments.

Once your `.env` file is set up, you can deploy the contract using the following command:

```bash
make deploy_fibonacci_validator
```

This command will log the address of the deployed contract like so:

```
== Return ==
0: address 0xFE5aBfb5E754e4AeFE1e8eC413ca6D2CCF99d5Ed
```

Make sure to save this address, as you'll need it for the next step.

Now, to call our verifier contract and check the inclusion of the proof along with the validation of the public inputs, use the following command based on the verifier you used:

* For Risc0:

  ```bash
  make verify_risc0_batch_inclusion FIBONACCI_VALIDATOR_ADDRESS=<FIBONACCI_VALIDATOR_ADDRESS> DATA_FILE_NAME=<DATA_FILE_NAME>
  ```
* For SP1:

  ```bash
  make verify_sp1_batch_inclusion FIBONACCI_VALIDATOR_ADDRESS=<FIBONACCI_VALIDATOR_ADDRESS> DATA_FILE_NAME=<DATA_FILE_NAME>
  ```

In these commands:

* `<FIBONACCI_VALIDATOR_ADDRESS>` is the address of the validator you deployed in the previous step.
* `<DATA_FILE_NAME>` is the name of the file where the aligned data for this proof was saved (including the `.json` extension)

When you run this command, it will gather all necessary information from the file containing the aligned data and send a transaction to the Fibonacci validator using the `cast send` tool, like so:

```bash
cast send --rpc-url $RPC_URL $FIBONACCI_VALIDATOR_ADDRESS \
	"verifyBatchInclusion(bytes32,bytes32,bytes32,bytes20,bytes32,bytes,uint256, bytes, string)" \
    $PROOF_COMMITMENT \
    $PUB_INPUT_COMMITMENT \
    $PROGRAM_ID_COMMITMENT \
    $PROOF_GENERATOR_ADDR \
    $BATCH_MERKLE_ROOT \
    $MERKLE_PROOF \
    $VERIFICATION_DATA_BATCH_INDEX \
    $PUB_INPUT \
    $VERIFIER_ID \
    --private-key $PRIVATE_KEY
```

If the output of this transaction indicates `success`, then we can confirm that our proof has been successfully included in Aligned. Additionally, this outcome verifies that the public inputs we generated match the expected values from the proof generation process.


# Proof Aggregation Service

## Aggregation Mode

Aggregation Mode is a standalone service, independent from the Aligned Verification Layer. You no longer need to interact with the verification layer to have your proofs verified—Aggregation Mode handles the entire process.

> **Note:** Aggregation Mode is currently available on the [`staging` branch](https://github.com/yetanotherco/aligned_layer/tree/staging).

### Reference Documentation

* [CLI Reference](/guides/10.1_aggregation_mode_cli) - Command-line interface for interacting with Aggregation Mode
* [SDK Reference](/guides/1.3_sdk_api_reference_aggregation) - Rust SDK API reference

***

### Proof Aggregation Service L2 integration example

This guide demonstrates how to build a dummy L2 application that integrates with Aligned's Proof Aggregation Service. The L2 does not post state diffs or any data to Ethereum, only commitments. The prover has to prove that:

1. The state database used in the proof must match the commitment stored in the on-chain contract. This is validated by computing the commitment of the received data in the zkvm and then exposing it as a public input.
2. The users performing the transfers have enough balance

After processing the transfers, the vm computes the commitment of the post state, which is exposed as a public input. The smart contract then updates the on-chain state root. If a user later wants to retrieve their state, the application must return it along with a Merkle proof, so they can verify it against the contract’s state root.

Notice a lot of checks that a real L2 should have are missing, since the focus are on the integration of Aligned.

The code can be viewed at `examples/l2`.

### L2 workflow overview

This Layer 2 (L2) system operates in two main steps:

* Off-chain execution and proof generation + verification with Aligned's Proof Verification Layer.
* On-chain state update via proof verification with Aligned's Proof Aggregation Service.

In Step 1, we execute user transfers and generate a zkVM-based proof of the state transition, which is submitted to Aligned’s verification layer.

In Step 2, once the proof is aggregated (every 24 hours), it is verified on-chain to update the global state.

#### Step 1: Off-Chain Execution + Proof Generation

1. Initialize State: Load or initialize the current system state.
2. Load Transfers: Retrieve or receive the user transfer data for this batch.
3. Execute in zkVM: Run the zkVM with the loaded transfers to compute the new state.
4. Generate Proof: Produce a zk-proof for the executed state transition committing the commitment of the received + the commitment of the new state.
5. Submit Proof to Aligned: Send the proof to Aligned Verification Layer
6. Save the binary proof locally for later on-chain verification.

#### Step 2: Proof Verification + On-Chain State Update

7. Load the proof binary: Retrieve the saved proof binary from disk.
8. Update On-Chain State: Call the smart contract method `updateStateTransition`, which:
   * Internally calls `verifyProofInclusion` on AlignedProofAggregationService which:
     1. Computes the proof commitment from the proof `public_inputs` and `program_id`.
     2. Uses the Merkle proof to reconstruct and validate the Merkle root.
     3. Confirms whether there exists and aggregated proof with that root.
   * Validates that the `initial_state_root` proof public input matches the on-chain state.
   * If valid, updates the on-chain state root to the `post_state_root`.

## Usage

#### Requirements

1. [Rust](https://www.rust-lang.org/tools/install): we have tested in v1.85.1
2. [Foundry](https://book.getfoundry.sh/getting-started/installation)
3. [Docker](https://docs.docker.com/engine/): for SP1 prover

Submodules of the repo should be imported by running on the root folder:

```shell
make submodules
```

You can run the example on:

* [Hoodi](#setup-hoodi)
* [Localnet](#setup-localnet)

### Setup Hoodi

#### 1. Create keystore

You can use cast to create a local keystore. If you already have one you can skip this step.

```bash
cast wallet new-mnemonic
```

Then you can import your created keystore using:

```bash
cast wallet import --interactive <path_to_keystore.json>
```

Then you need to obtain some funds to pay for gas and proof verification. You can do this by using this [faucet](https://cloud.google.com/application/web3/faucet/ethereum/hoodi)

*This same wallet is used to send the proof via aligned, so you'll also need to fund it on aligned. Follow this* [*guide*](https://docs.alignedlayer.com/guides/0_submitting_proofs#id-2.-send-funds-to-aligned)*.*

#### 2. Deploy the contract

* Generate the base `.env`:

```shell
make gen_env_contract_hoodi
```

* Get the program ID of the l2 program you are proving:

```shell
make generate_program_id
```

* Complete the following fields `contracts/.env` file:
  * `PROGRAM_ID=` (use the previously generated ID, you can re check with a `cat ./crates/l2/programs_ids.json` )
  * `PRIVATE_KEY`: the private key used for the deployment, it needs to have some funds to pay for the deployment.
  * `OWNER_ADDRESS`: you have to provide the *address of the wallet created in step `1.`*.
* Deploy the contracts with:

```shell
make deploy_contract
```

*Save the output contract address.*

#### 3. Setup the L2

* Generate the base `.env` run:

```shell
make gen_env_l2_hoodi
```

* Complete the missing fields on the `.env`:
  * `PRIVATE_KEY_STORE_PATH`: The path to the keystore created in `1.`.
  * `PRIVATE_KEY_STORE_PASSWORD`: The password of the keystore crated in step `1.`.
  * `STATE_TRANSITION_CONTRACT_ADDRESS`: The address of the contract deployed in step `2.`

Finally [run the l2](#running-the-l2).

### Setup Localnet

You can also run this example on a local devnet. To get started, navigate to the root of the Aligned repository

* Start Ethereum package and the Batcher

```shell
# This will start the local net
make ethereum_package_start
# Start the batcher
make batcher_start_ethereum_package
```

* Navigate back to the example directory:

```shell
cd examples/l2
```

* Generate the `.env` files for the contracts and L2:

```shell
make gen_env_contract_devnet
make gen_env_l2_devnet
```

* Generate a pre funded wallet (or create one as specified [previously here](#1-create-keystore)):

```shell
# This will generate the keystore and fund it on aligned
make gen_devnet_owner_wallet
```

* Generate the program ID of the program that is going to be proven:

```shell
make generate_program_id
```

* Set the generated program ID on `contracts/.env`.
* Deploy the contract

```shell
make deploy_contract
```

* Set the output address of the contract in `.env`
* [run the l2](#running-the-l2)

### Running the L2

* Set up the initial State

```shell
make init_state
```

* Perform the L2 account updates and prove them in the zkvm:

```shell
make prove_state_transition
```

* Wait 24 hs for the proof to be aggregated, or if running locally, run the aggregator with either:

  ````
  ```make proof_aggregator_start_ethereum_package AGGREGATOR=sp1```
  ````

  or with cuda: `make proof_aggregator_start_gpu_ethereum_package AGGREGATOR=sp1`
* Update state transition on chain:

```shell
make update_state_on_chain
```

You should see a transaction receipt in the console and after the stateRoot updated on-chain.


# SDK Intro

The Aligned SDK aims to help developers interact with Aligned in a simple way. Using the Aligned SDK, you can do things like submitting and verifying proofs through the Aligned Batcher, as well as checking the inclusion of the verified proofs on-chain. This guide provides an overview of the SDK, its installation, usage, and API details.

You can check the list of supported verifiers [here](/architecture/0_supported_verifiers).

## Installation

To use this SDK in your Rust project, add the following to your `Cargo.toml`:

```toml
[dependencies]
aligned-sdk = { git = "https://github.com/yetanotherco/aligned_layer", tag="v0.20.0" }
```

To find the latest release tag go to [releases](https://github.com/yetanotherco/aligned_layer/releases) and copy the version of the release that has the `latest` badge.

## Hello World

To get the SDK up and running in your project, you must first import it

```rust
use aligned_sdk::common::types::{PriceEstimate, AlignedVerificationData, Network, ProvingSystemId, VerificationData};
use aligned_sdk::verification_layer::{estimate_fee, submit_and_wait, get_nonce_from_ethereum};
```

And then you can do a simple call of, for example, `get_nonce_from_ethereum`

```rust
const NETWORK: Network = Network::Hoodi;

fn main() {
    let rpc_url = args.rpc_url.clone();
    let keystore_password = rpassword::prompt_password("Enter keystore password: ")
        .expect("Failed to read keystore password");
    let wallet = LocalWallet::decrypt_keystore(args.keystore_path, &keystore_password)
        .expect("Failed to decrypt keystore")
        .with_chain_id(560048u64);

    // Call to SDK:
    let nonce = get_nonce_from_ethereum(&rpc_url, wallet.address(), NETWORK).await
    .expect("Failed to get next nonce");
}
```

Or you can make a more complex call to submit a proof:

(code extract from [ZKQuiz example](/guides/2_build_your_first_aligned_application#app))

```rust
fn main() {
    let rpc_url = args.rpc_url.clone();
    let verification_data = VerificationData {
        proving_system: ProvingSystemId::SP1,
        proof,
        proof_generator_addr: wallet.address(),
        vm_program_code: Some(ELF.to_vec()),
        verification_key: None,
        pub_input: None,
    };
    let keystore_password = rpassword::prompt_password("Enter keystore password: ")
        .expect("Failed to read keystore password");
    let wallet = LocalWallet::decrypt_keystore(args.keystore_path, &keystore_password)
        .expect("Failed to decrypt keystore")
        .with_chain_id(560048u64);
    let max_fee = estimate_fee(&rpc_url, PriceEstimate::Instant)
        .await
        .expect("failed to fetch gas price from the blockchain");

    // Call to SDK:
    match submit_and_wait_verification(
        &rpc_url,
        Network::Hoodi,
        &verification_data,
        max_fee,
        wallet.clone(),
        nonce
    )
    .await
    {
        Ok(maybe_aligned_verification_data) => match maybe_aligned_verification_data {
            Some(aligned_verification_data) => {
                println!(
                    "Proof submitted and verified successfully on batch {}",
                    hex::encode(aligned_verification_data.batch_merkle_root)
                );

            }
            None => {
                println!("Proof submission failed. No verification data");
            }
        },
        Err(e) => {
            println!("Proof verification failed: {:?}", e);
        }
    }
}
```

In the [next section,](/guides/1.2_sdk_api_reference) we will dive deeper into what does each argument mean, and what other functions does Aligned SDK contain.


# Verification Layer SDK

## API Reference

### `submit`

Submits a proof to the batcher to be verified and returns an aligned verification data struct.

```rust
pub async fn submit(
    network: Network,
    verification_data: &VerificationData,
    max_fee: U256,
    wallet: Wallet<SigningKey>,
    nonce: U256,
) -> Result<AlignedVerificationData, errors::SubmitError>
```

#### Arguments

* `network` - The network on which the proof will be submitted (`devnet | sepolia | mainnet | hoodi`)
* `verification_data` - The verification data for the proof.
* `max_fee` - The maximum fee that the submitter is willing to pay for the proof verification.
* `wallet` - The wallet used to sign the proof. Should be using correct chain id. See `get_chain_id`.
* `nonce` - The nonce of the submitter address. See `get_nonce_from_ethereum`.

#### Returns

* `Result<AlignedVerificationData, SubmitError>` - An aligned verification data or an error.

#### Errors

* `MissingRequiredParameter` if the verification data vector is empty.
* `ProtocolVersionMismatch` if the version of the SDK is lower than the expected one.
* `UnexpectedBatcherResponse` if the batcher doesn't respond with the expected message.
* `SerializationError` if there is an error deserializing the message sent from the batcher.
* `WebSocketConnectionError` if there is an error connecting to the batcher.
* `WebSocketClosedUnexpectedlyError` if the connection with the batcher is closed unexpectedly.
* `InvalidSignature` if the signature is invalid.
* `InvalidNonce` if the nonce is invalid.
* `InvalidMaxFee` if the max fee is invalid.
* `InvalidProof` if the proof is invalid.
* `ProofTooLarge` if the proof is too large.
* `InsufficientBalance` if the sender balance is not enough or unlocked
* `ProofQueueFlushed` if there is an error in the batcher and the proof queue is flushed.
* `NotAContract(address)` if you are trying to send to an address that is not a contract. This generally occurs if you have misconfigured the `environment` parameter.
* `ProofReplaced` if the proof has been replaced.
* `GenericError` if the error doesn't match any of the previous ones.

### `submit_multiple`

Submits multiple proofs to the batcher to be verified and returns an aligned verification data array.

```rust
pub async fn submit_multiple(
    network: Network,
    verification_data: &[VerificationData],
    max_fee: U256,
    wallet: Wallet<SigningKey>,
    nonce: U256,
) -> Result<Vec<AlignedVerificationData>, errors::SubmitError>
```

#### Arguments

* `network` - The network on which the proof will be submitted (`devnet | sepolia | mainnet | hoodi`)
* `verification_data` - A verification data array.
* `max_fee` - The maximum fee that the submitter is willing to pay for the verification for each proof.
* `wallet` - The wallet used to sign the proof. Should be using correct chain id. See `get_chain_id`.
* `nonce` - The nonce of the submitter address. See `get_nonce_from_ethereum`.

#### Returns

* `Result<Vec<AlignedVerificationData>, SubmitError>` - An aligned verification data array or an error.

#### Errors

* `MissingRequiredParameter` if the verification data vector is empty.
* `ProtocolVersionMismatch` if the version of the SDK is lower than the expected one.
* `UnexpectedBatcherResponse` if the batcher doesn't respond with the expected message.
* `SerializationError` if there is an error deserializing the message sent from the batcher.
* `WebSocketConnectionError` if there is an error connecting to the batcher.
* `WebSocketClosedUnexpectedlyError` if the connection with the batcher is closed unexpectedly.
* `InvalidSignature` if the signature is invalid.
* `InvalidNonce` if the nonce is invalid.
* `InvalidMaxFee` if the max fee is invalid.
* `InvalidProof` if the proof is invalid.
* `ProofTooLarge` if the proof is too large.
* `InsufficientBalance` if the sender balance is not enough or unlocked
* `ProofQueueFlushed` if there is an error in the batcher and the proof queue is flushed.
* `ProofReplaced` if the proof has been replaced.
* `GenericError` if the error doesn't match any of the previous ones.

### `submit_and_wait_verification`

Submits a proof to the batcher to be verified, waits for the verification on ethereum and returns an aligned verification data struct.

```rust
pub async fn submit_and_wait_verification(
    eth_rpc_url: &str,
    network: Network,
    verification_data: &VerificationData,
    max_fee: U256,
    wallet: Wallet<SigningKey>,
    nonce: U256,
) -> Result<AlignedVerificationData, errors::SubmitError>
```

#### Arguments

* `eth_rpc_url` - The URL of the Ethereum RPC node.
* `network` - The network on which the verification will be done (`devnet | sepolia | mainnet | hoodi`)
* `verification_data` - The verification data for the proof.
* `max_fee` - The maximum fee that the submitter is willing to pay for the proof verification.
* `wallet` - The wallet used to sign the proof. Should be using correct chain id. See `get_chain_id`.
* `nonce` - The nonce of the submitter address. See `get_nonce_from_ethereum`.

#### Returns

* `Result<AlignedVerificationData, SubmitError>` - An aligned verification data or an error.

#### Errors

* `MissingRequiredParameter` if the verification data vector is empty.
* `ProtocolVersionMismatch` if the version of the SDK is lower than the expected one.
* `UnexpectedBatcherResponse` if the batcher doesn't respond with the expected message.
* `SerializationError` if there is an error deserializing the message sent from the batcher.
* `WebSocketConnectionError` if there is an error connecting to the batcher.
* `WebSocketClosedUnexpectedlyError` if the connection with the batcher is closed unexpectedly.
* `EthereumProviderError` if there is an error in the connection with the RPC provider.
* `HexDecodingError` if there is an error decoding the Aligned service manager contract address.
* `BatchVerificationTimeout` if there is a timeout waiting for the batch verification.
* `InvalidSignature` if the signature is invalid.
* `InvalidNonce` if the nonce is invalid.
* `InvalidMaxFee` if the max fee is invalid.
* `InvalidProof` if the proof is invalid.
* `ProofTooLarge` if the proof is too large.
* `InsufficientBalance` if the sender balance is not enough or unlocked
* `ProofQueueFlushed` if there is an error in the batcher and the proof queue is flushed.
* `NotAContract(address)` if you are trying to send to an address that is not a contract. This generally occurs if you have misconfigured the `environment` parameter.
* `ProofReplaced` if the proof has been replaced.
* `GenericError` if the error doesn't match any of the previous ones.

### `submit_multiple_and_wait_verification`

Submits multiple proofs to the batcher for verification, waits for verification on Ethereum, and returns an array of `Result`s containing aligned verification data that indicates whether each proof was successfully submitted. If a timeout occurs while waiting for verification, an additional `Err` is appended to the end of the returned array.

```rust
pub async fn submit_multiple_and_wait_verification(
    eth_rpc_url: &str,
    network: Network,
    verification_data: &[VerificationData],
    max_fee: U256,
    wallet: Wallet<SigningKey>,
    nonce: U256
) -> Vec<Result<AlignedVerificationData, errors::SubmitError>>
```

#### Arguments

* `eth_rpc_url` - The URL of the Ethereum RPC node.
* `network` - The network on which the verification will be done (`devnet | sepolia | mainnet | hoodi`)
* `verification_data` - A verification data array.
* `max_fee` - The maximum fee that the submitter is willing to pay for the proof verification.
* `wallet` - The wallet used to sign the proof. Should be using correct chain id. See `get_chain_id`.
* `nonce` - The nonce of the submitter address. See `get_nonce_from_ethereum`.

#### Returns

* `Result<Vec<AlignedVerificationData>, SubmitError>` - An aligned verification data array or an error.

#### Errors

* `MissingRequiredParameter` if the verification data vector is empty.
* `ProtocolVersionMismatch` if the version of the SDK is lower than the expected one.
* `UnexpectedBatcherResponse` if the batcher doesn't respond with the expected message.
* `SerializationError` if there is an error deserializing the message sent from the batcher.
* `WebSocketConnectionError` if there is an error connecting to the batcher.
* `WebSocketClosedUnexpectedlyError` if the connection with the batcher is closed unexpectedly.
* `EthereumProviderError` if there is an error in the connection with the RPC provider.
* `HexDecodingError` if there is an error decoding the Aligned service manager contract address.
* `BatchVerificationTimeout` if there is a timeout waiting for the batch verification.
* `InvalidSignature` if the signature is invalid.
* `InvalidNonce` if the nonce is invalid.
* `InvalidMaxFee` if the max fee is invalid.
* `InvalidProof` if the proof is invalid.
* `ProofTooLarge` if the proof is too large.
* `InsufficientBalance` if the sender balance is not enough or unlocked
* `ProofQueueFlushed` if there is an error in the batcher and the proof queue is flushed.
* `NotAContract(address)` if you are trying to send to an address that is not a contract. This generally occurs if you have misconfigured the `environment` parameter.
* `ProofReplaced` if the proof has been replaced.
* `GenericError` if the error doesn't match any of the previous ones.

### `is_proof_verified`

Checks if the proof has been verified with Aligned and is included in the batch on-chain.

```rust
pub async fn is_proof_verified(
    aligned_verification_data: AlignedVerificationData,
    network: Network,
    eth_rpc_url: &str
) -> Result<bool, errors::VerificationError>
```

#### Arguments

* `aligned_verification_data` - The aligned verification data obtained when submitting the proofs.
* `network` - The network on which the verification will be done (`devnet | sepolia | mainnet | hoodi`)
* `eth_rpc_url` - The URL of the Ethereum RPC node.

#### Returns

* `Result<bool, VerificationError>` - A boolean indicating whether the proof was verified on-chain and is included in the batch or an error.

#### Errors

* `EthereumProviderError` if there is an error in the connection with the RPC provider.
* `EthereumCallError` if there is an error in the Ethereum call.
* `HexDecodingError` if there is an error decoding the Aligned service manager contract address.

### `get_nonce_from_ethereum`

Returns the nonce for a given address in Ethereum from aligned payment service contract. Note that it might be out of sync if you recently sent proofs. For that see [`get_nonce_from_batcher`](#get_nonce_from_batcher)

```rust
pub async fn get_nonce_from_ethereum(
    eth_rpc_url: &str,
    submitter_addr: Address,
    network: Network,
) -> Result<U256, errors::NonceError>
```

#### Arguments

* `eth_rpc_url` - The URL of the Ethereum RPC node.
* `submitter_addr` - The user address for which the nonce will be retrieved.
* `network` - The network from which the nonce will be retrieved.

#### Returns

* `Result<U256, NonceError>` - The nonce to use or an error.

#### Errors

* `EthRpcError` if the batcher has an error in the Ethereum call when retrieving the nonce if not already cached.

### `get_nonce_from_batcher`

Returns the next nonce for a given address from the batcher.

You should prefer this method instead of [`get_nonce_from_ethereum`](#get_nonce_from_ethereum) if you have recently sent proofs, as the batcher proofs might not yet be on ethereum, producing an out-of-sync nonce with the payment service contract on ethereum

```rust
pub async fn get_nonce_from_batcher(
    network: Network,
    address: Address,
) -> Result<U256, GetNonceError> {
```

#### Arguments

* `network` - The network from which the nonce will be retrieved.
* `address` - The user address for which the nonce will be retrieved.

#### Returns

* `Result<U256, NonceError>` - The next nonce of the proof submitter account.

#### Errors

* `EthRpcError` if the batcher has an error in the Ethereum call when retrieving the nonce if not already cached.

### `get_last_max_fee`

Retrieves the `max_fee` of the proof with the highest nonce in the batcher queue for a given address.

This value represents the maximum fee limit that can be used when submitting the next proof. To increase the fee limit for a new proof, you must first bump the fee of the previous proofs queued in the batcher.

Read more here: <https://docs.alignedlayer.com/architecture/1\\_proof\\_verification\\_layer/1\\_batcher#max-fee-priority-queue>

```rust
pub async fn get_last_max_fee(
    network: Network,
    address: Address,
) -> Result<U256, GetLastMaxFeeError>
```

#### Arguments

* `network` - The network from which to retrieve the last `max_fee`.
* `address` - The user address whose last `max_fee` will be retrieved.

#### Returns

* `Result<U256, GetLastMaxFeeError>` - The `max_fee` of the proof with the highest nonce for the given user, or `U256::MAX` if the user has no proofs in the queue.

#### Errors

* `ConnectionFailed` if there is an error connecting to the batcher.
* `ProtocolMismatch` if the protocol version doesn't match.
* `SerializationError` if there is an error serializing/deserializing the message.
* `InvalidRequest` if the request is invalid.
* `UnexpectedResponse` if the batcher responds with an unexpected message.
* `GenericError` if the error doesn't match any of the previous ones.

#### Notes

* Returns `U256::MAX` (2^256 - 1) when no proofs are present in the queue for the user.

### `get_chain_id`

Returns the chain ID for a given rpc url.

Should be used before submitting proofs to the batcher.

```rust
pub async fn get_chain_id(
  eth_rpc_url: &str
) -> Result<u64, errors::ChainIdError>
```

#### Arguments

* `eth_rpc_url` - The URL of the Ethereum RPC node.

#### Returns

* `Result<u64, ChainIdError>` - The chain ID to use or an error.

#### Errors

* `EthereumProviderError` if there is an error in the connection with the RPC provider.
* `EthereumCallError` if there is an error in the Ethereum call.

Wallet chain ID needs to be set with:

```rust
wallet = wallet.with_chain_id(chain_id);
```

### `estimate_fee`

Estimates the fee the user would have to pay for submitting a proof to Aligned. Depending on the priority the user wants to have in the batch, the `estimate` parameter can be set.

```rust
pub async fn estimate_fee(
    eth_rpc_url: &str,
    fee_estimation_type: FeeEstimationType,
) -> Result<U256, errors::MaxFeeEstimateError>
```

#### Arguments

* `eth_rpc_url` - The URL of the Ethereum RPC node.
* `fee_estimation_type` - Enum specifying the type of price estimate: Default, Instant. Custom(usize)

#### Returns

* `Result<U256, MaxFeeEstimateError>` - the estimated `max_fee` depending on the batch inclusion preference of the user.

#### Errors

* `EthereumProviderError` if there is an error in the connection with the RPC provider.
* `EthereumCallError` if there is an error in the Ethereum call.

### `estimate_fee_per_proof_with_rpc`

Returns the `fee_per_proof` based on the current gas price for a batch compromised of `num_proofs_per_batch`

```rust
pub async fn estimate_fee_per_proof_with_rpc(
    num_proofs_in_batch: usize,
    eth_rpc_url: &str,
) -> Result<U256, errors::FeeEstimateError>
```

#### Arguments

* `num_proofs_in_batch` - number of proofs within a batch.
* `eth_rpc_url` - The URL of the users Ethereum RPC node.

#### Returns

* `Result<U256, errors::FeeEstimateError>` - The fee per proof of a batch as a `U256`.

#### Errors

-`EthereumProviderError` if there is an error in the connection with the RPC provider. -`EthereumGasPriceError` if there is an error retrieving the Ethereum gas price.

### `calculate_fee_per_proof_with_gas_price`

Calculates the fee per proof based on a given batch size and gas price. This is a pure calculation function that doesn't make any network calls.

```rust
pub fn calculate_fee_per_proof_with_gas_price(
    num_proofs_in_batch: usize, 
    gas_price: U256
) -> U256
```

#### Arguments

* `num_proofs_in_batch` - number of proofs within a batch.
* `gas_price` - Current gas price (in wei).

#### Returns

* `U256` - The estimated fee per individual proof (in wei).

#### Notes

This function is used internally by both `estimate_fee` and `estimate_fee_per_proof_with_rpc`. It performs the core fee calculation logic without any network dependencies.

### `deposit_to_aligned`

Funds the batcher payment service in name of the signer.

```rust
pub async fn deposit_to_aligned(
    amount: U256,
    signer: SignerMiddleware<Provider<Http>, LocalWallet>,
    network: Network,
) -> Result<ethers::types::TransactionReceipt, errors::PaymentError> {
```

#### Arguments

`amount` - The amount to be paid. `signer` - The signer middleware of the payer. `network` - The network on which the payment will be done.

#### Returns

The receipt of the payment transaction.

#### Errors

`SendError` if there is an error sending the transaction. `SubmitError` if there is an error submitting the transaction. `PaymentFailed` if the payment failed.

### `get_balance_in_aligned`

Queries a User's balance that was deposited in Aligned

```rust
pub async fn get_balance_in_aligned(
    user: Address,
    eth_rpc_url: &str,
    network: Network,
) -> Result<U256, errors::BalanceError> {
```

#### Arguments

`user` - The address of the user. `eth_rpc_url` - The URL of the Ethereum RPC node. `network` - The network on which the balance will be checked.

#### Returns

* `Result<U256, errors::BalanceError>` - The balance of the user in the payment service.

#### Errors

* `EthereumProviderError` if there is an error in the connection with the RPC provider.
* `EthereumCallError` if there is an error in the Ethereum call.

### `lock_balance_in_aligned`

Locks the balance of a user in the Aligned payment service.

```rust
pub async fn lock_balance_in_aligned(
    signer: &SignerMiddleware<Provider<Http>, LocalWallet>,
    network: Network,
) -> Result<ethers::types::TransactionReceipt, errors::PaymentError>
```

#### Arguments

* `signer` - The signer middleware containing the user's wallet and provider.
* `network` - The network on which the lock operation will be performed.

#### Returns

* `Result<ethers::types::TransactionReceipt, errors::PaymentError>` - The transaction receipt of the lock operation.

#### Description

This function locks the user's balance, preventing it from being withdrawn. Locked balances can be used for proof verification payments but cannot be withdrawn until they are unlocked using `unlock_balance_in_aligned` and the lock period expires.

#### Errors

* `SendError` if there is an error sending the transaction.
* `SubmitError` if there is an error submitting the transaction.

### `unlock_balance_in_aligned`

Unlocks the balance of a user in the Aligned payment service.

```rust
pub async fn unlock_balance_in_aligned(
    signer: &SignerMiddleware<Provider<Http>, LocalWallet>,
    network: Network,
) -> Result<ethers::types::TransactionReceipt, errors::PaymentError>
```

#### Arguments

* `signer` - The signer middleware containing the user's wallet and provider.
* `network` - The network on which the unlock operation will be performed.

#### Returns

* `Result<ethers::types::TransactionReceipt, errors::PaymentError>` - The transaction receipt of the unlock operation.

#### Description

This function initiates an unlock request for the user's balance. After calling this function, the user's balance will be locked for a certain period before it can be withdrawn. Use `get_unlock_block_time` to check when the balance can be withdrawn.

#### Errors

* `SendError` if there is an error sending the transaction.
* `SubmitError` if there is an error submitting the transaction.

### `get_unlock_block_time`

Returns the timestamp when a user's balance will be unlocked and available for withdrawal.

```rust
pub async fn get_unlock_block_time(
    user: Address,
    eth_rpc_url: &str,
    network: Network,
) -> Result<u64, errors::BalanceError>
```

#### Arguments

* `user` - The address of the user to check the unlock time for.
* `eth_rpc_url` - The URL of the Ethereum RPC node.
* `network` - The network on which to check the unlock time.

#### Returns

* `Result<u64, errors::BalanceError>` - The timestamp when the user's balance will be unlocked.

#### Description

After calling `unlock_balance_in_aligned`, users must wait for the lock period before they can withdraw their funds using `withdraw_balance_from_aligned`.

#### Errors

* `EthereumProviderError` if there is an error in the connection with the RPC provider.
* `EthereumCallError` if there is an error in the Ethereum call.

### `withdraw_balance_from_aligned`

Withdraws a specified amount from the user's balance in the Aligned payment service.

```rust
pub async fn withdraw_balance_from_aligned(
    signer: &SignerMiddleware<Provider<Http>, LocalWallet>,
    network: Network,
    amount: U256,
) -> Result<ethers::types::TransactionReceipt, errors::PaymentError>
```

#### Arguments

* `signer` - The signer middleware containing the user's wallet and provider.
* `network` - The network on which the withdrawal will be performed.
* `amount` - The amount to withdraw from the user's balance.

#### Returns

* `Result<ethers::types::TransactionReceipt, errors::PaymentError>` - The transaction receipt of the withdrawal operation.

#### Description

This function can only be called after the balance has been unlocked using `unlock_balance_in_aligned` and the lock period has expired. Use `get_unlock_block_time` to check when the withdrawal becomes available.

#### Errors

* `SendError` if there is an error sending the transaction.
* `SubmitError` if there is an error submitting the transaction.

### `get_vk_commitment`

Returns the commitment for the verification key, taking into account the corresponding proving system.

```rust
pub fn get_vk_commitment(
    verification_key_bytes: &[u8],
    proving_system: ProvingSystemId,
) -> [u8; 32]
```

#### Arguments

* `verification_key_bytes` - The serialized contents of the verification key.
* `proving_system` - The corresponding proving system ID.

#### Returns

* `[u8; 32]` - The commitment.

#### Errors

* None.

### `save_response`

Saves AlignedVerificationData in a file.

```rust
pub fn save_response(
    batch_inclusion_data_directory_path: PathBuf,
    aligned_verification_data: &AlignedVerificationData,
) -> Result<(), errors::FileError>
```

#### Arguments

-`batch_inclusion_data_directory_path` - The path of the directory where the data will be saved. -`aligned_verification_data` - The aligned verification data to be saved.

#### Returns

* `Result<(), errors::FileError>` - Ok if the data is saved successfully.

#### Errors

* `FileError` if there is an error writing the data to the file.


# Aggregation Mode SDK

## API Reference

### `AggregationModeGatewayProvider`

The gateway provider handles communication with the Aggregation Mode Gateway for submitting proofs and querying proof status.

***

### `AggregationModeGatewayProvider::new`

Creates a new gateway provider without a signer. Useful for read-only operations like checking nonces or receipts.

```rust
pub fn new(network: Network) -> Result<Self, GatewayError>
```

#### Arguments

* `network` - The network to connect to (`Devnet | Hoodi | Mainnet`)

#### Returns

* `Result<AggregationModeGatewayProvider, GatewayError>` - A gateway provider instance or an error.

***

### `AggregationModeGatewayProvider::new_with_signer`

Creates a new gateway provider with a signer. Required for submitting proofs.

```rust
pub fn new_with_signer(network: Network, signer: S) -> Result<Self, GatewayError>
```

#### Arguments

* `network` - The network to connect to (`Devnet | Hoodi | Mainnet`)
* `signer` - A signer implementing the `Signer` trait (e.g., `PrivateKeySigner`)

#### Returns

* `Result<AggregationModeGatewayProvider, GatewayError>` - A gateway provider instance or an error.

***

### `get_nonce_for`

Retrieves the current nonce for a given address.

```rust
pub async fn get_nonce_for(
    &self,
    address: String,
) -> Result<GatewayResponse<NonceResponse>, GatewayError>
```

#### Arguments

* `address` - The Ethereum address to query the nonce for.

#### Returns

* `Result<GatewayResponse<NonceResponse>, GatewayError>` - The nonce response or an error.

***

### `get_receipts_for`

Retrieves proof submission receipts for a given address.

```rust
pub async fn get_receipts_for(
    &self,
    address: String,
    nonce: Option<u64>,
) -> Result<GatewayResponse<ReceiptsResponse>, GatewayError>
```

#### Arguments

* `address` - The Ethereum address to query receipts for.
* `nonce` - Optional nonce to filter receipts by a specific submission.

#### Returns

* `Result<GatewayResponse<ReceiptsResponse>, GatewayError>` - The receipts response or an error.

***

### `submit_sp1_proof`

Submits an SP1 proof to the Aggregation Mode Gateway.

```rust
pub async fn submit_sp1_proof(
    &self,
    proof: &SP1ProofWithPublicValues,
    vk: &SP1VerifyingKey,
) -> Result<GatewayResponse<SubmitProofResponse>, GatewayError>
```

#### Arguments

* `proof` - The SP1 proof with public values.
* `vk` - The SP1 verifying key.

#### Returns

* `Result<GatewayResponse<SubmitProofResponse>, GatewayError>` - The submission response containing a task ID, or an error.

#### Errors

* `SignerNotConfigured` - If the provider was created without a signer.
* `ProofSerialization` - If there is an error serializing the proof or verifying key.
* `MessageSignature` - If there is an error signing the submission message.
* `Request` - If there is a network error communicating with the gateway.
* `Api` - If the gateway returns an error response.

***

### `ProofAggregationServiceProvider`

The blockchain provider handles verification of proofs on-chain by querying the AlignedProofAggregationService contract.

***

### `ProofAggregationServiceProvider::new`

Creates a new blockchain provider for verifying proofs on-chain.

```rust
pub fn new(network: Network, rpc_url: String, beacon_client_url: String) -> Self
```

#### Arguments

* `network` - The network to connect to (`Devnet | Hoodi | Mainnet`)
* `rpc_url` - The Ethereum RPC provider URL.
* `beacon_client_url` - The Beacon chain client URL.

#### Returns

* `ProofAggregationServiceProvider` - A blockchain provider instance.

***

### `check_proof_verification`

Checks if a proof has been verified on-chain.

```rust
pub async fn check_proof_verification(
    &self,
    from_block: Option<u64>,
    verification_data: AggregationModeVerificationData,
) -> Result<ProofStatus, ProofVerificationAggModeError>
```

#### Arguments

* `from_block` - Optional block number to start searching from. Defaults to current block minus 7500 blocks (\~25 hours).
* `verification_data` - The verification data containing the proving system type, verifying key hash, and public inputs.

#### Returns

* `Result<ProofStatus, ProofVerificationAggModeError>` - The proof status or an error.

#### Proof Status

* `Verified { merkle_path, merkle_root }` - The proof was found and verified in an aggregated batch.
* `Invalid` - The proof was found but Merkle root verification failed.
* `NotFound` - The proof was not found in any aggregated batch.

#### Errors

* `EthereumProviderError` - If there is an error communicating with the Ethereum RPC.
* `BeaconClient` - If there is an error communicating with the Beacon chain.
* `EventDecoding` - If there is an error decoding the on-chain event data.

***

## Types

### `Network`

```rust
pub enum Network {
    Devnet,   // Chain ID: 31337
    Hoodi,    // Chain ID: 560048
    Mainnet,  // Chain ID: 1
}
```

### `AggregationModeVerificationData`

```rust
pub enum AggregationModeVerificationData {
    SP1 {
        vk: [u8; 32],
        public_inputs: Vec<u8>,
    },
}
```

### `GatewayError`

```rust
pub enum GatewayError {
    Request(String),
    Api { status: u16, message: String },
    SignerNotConfigured,
    ProofSerialization(String),
    MessageSignature(String),
}
```

### `ProofStatus`

```rust
pub enum ProofStatus {
    Verified {
        merkle_path: Vec<[u8; 32]>,
        merkle_root: [u8; 32],
    },
    Invalid,
    NotFound,
}
```


# Generating proofs for Aligned

## SP1

### Dependencies

This guide assumes that:

* sp1 prover installed (instructions [here](https://docs.succinct.xyz/docs/sp1/getting-started/install))
* sp1 project to generate the proofs (instructions [here](https://docs.succinct.xyz/docs/sp1/getting-started/quickstart))
* aligned installed (instructions [here](/introduction/1_try_aligned#quickstart))

### How to generate a proof

> Aligned only verifies SP1 in a compressed version. You can check you are using compressed by opening script/src/main.rs and check that the proof is generated with `client.prove_compressed` instead of `client.prove`.

First, open a terminal and navigate to the script folder in the sp1 project directory

Then, run the following command to generate a proof:

```bash
cargo run --release
```

### How to get the proof verified by Aligned

After generating the proof, you will have to find two different files:

* **proof file**: usually found under `script` directory, with the name `proof.json` or similar
* **elf file**: usually found under `program/elf/` directory

Then, you can send the proof to the Aligned network by running the following command

```bash
aligned submit \
--proving_system SP1 \
--proof <proof_path> \
--vm_program <vm_program_path> \
--batcher_url wss://batcher.alignedlayer.com \
--proof_generator_addr <proof_generator_addr> \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com 
```

Where `proof_path` is the path to the proof file, `vm_program_path` is the path to the ELF file. `proof_generator_addr` is an optional parameter that works as a helper for some applications where you can be frontrunned.

For more instructions on how to submit proofs, check the [Submitting proofs guide](/guides/0_submitting_proofs).

## Gnark

### Dependencies

This guide assumes that:

* Gnark library is installed. If not, install it using the following command inside your Go module:

```bash
go get github.com/consensys/gnark@v0.12.0
```

* Gnark project to generate the proofs' instructions [here](https://docs.gnark.consensys.io/category/how-to)

### How to generate a proof

Open a terminal and navigate to the Gnark project directory. Then, run the following command to generate the proof:

```bash
go run circuit.go
```

### How to get the proof verified by Aligned

After generating the proof, you will have to have three different files:

* proof file
* verification key file
* public input file

For a detailed guide on how to generate those files, refer to our [detailed guide](https://github.com/yetanotherco/aligned_layer/blob/testnet/docs/3_guides/3.2_generate_gnark_proof.md).

Then, you can send the proof to the Aligned network by running the following command

```bash
aligned submit \
--proving_system GnarkPlonkBn254 \
--proof <proof_path> \
--public_input <public_input_path>
--vk <verification_key_path> \
--batcher_url wss://batcher.alignedlayer.com \
--proof_generator_addr <proof_generator_addr> \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com 
```

Where proof path is the path to the proof file, `public_input_path` is the path to the public input file, and `verification_key_path` is the path to the verification key file.

For more instructions on how to submit proofs, check the [Submitting proofs guide](/guides/0_submitting_proofs).

## Risc0

### Dependencies

This guide assumes that:

* Risc0 toolchain installed (instructions [here](https://dev.risczero.com/api/zkvm/quickstart#1-install-the-risc-zero-toolchain))
* Risc0 project to generate the proofs (instructions [here](https://dev.risczero.com/api/zkvm/quickstart#2-create-a-new-project))
* Aligned installed (instructions [here](/introduction/1_try_aligned#quickstart))

### How to generate a proof

First, open the risc0 host file and add the following code to export proof, image id & public input needed by Aligned.

```rust
fn main() {
    // your code here

    // <proof_file_path> is the path where the proof will be saved
    // Note that we serialize receipt.inner to avoid serializing the public inputs along with the proof
    let serialized = bincode::serialize(&receipt.inner).expect("Failed to serialize the receipt");
    std::fs::write("<proof_file_path", serialized).expect("Failed to write proof file");

    // <METHOD_ID> is the method id of the function you want to prove
    // <method_id_file_path> is the path where the method id will be saved
    std::fs::write("<method_id_file_path>", convert(&<METHOD_ID>))
            .expect("Failed to write method_id file");

    // <pub_input_file_path> is the path where the public input will be saved
    std::fs::write("<pub_input_file_path>", receipt.journal.bytes)
            .expect("Failed to write pub_input file");
}


// Convert u32 array to u8 array for storage
pub fn convert(data: &[u32; 8]) -> [u8; 32] {
    let mut res = [0; 32];
    for i in 0..8 {
        res[4 * i..4 * (i + 1)].copy_from_slice(&data[i].to_le_bytes());
    }
    res
}
```

Note that METHOD\_ID will be imported from guest, but it will be under a different name.

Then run the following command to generate the proof:

```bash
cargo run --release
```

### How to get the proof verified by Aligned

After generating the proof, you will have to find three different files:

* Proof file
* Image id file
* Public input file

Then, you can send the proof to the Aligned network by running the following command

```bash
aligned submit \
  --proving_system Risc0 \
  --proof <proof_file_path> \
  --vm_program <method_id_file_path> \
  --public_input <pub_input_file_path> \
  --batcher_url wss://batcher.alignedlayer.com \
  --proof_generator_addr <proof_generator_addr> \
  --rpc_url https://ethereum-hoodi-rpc.publicnode.com \
  --payment_service_addr 0x815aeCA64a974297942D2Bbf034ABEe22a38A003
```

For more instructions on how to submit proofs, check the [Submitting proofs guide](/guides/0_submitting_proofs).

## ZkRust

`zkRust` is a CLI tool maintained by Aligned that aims to simplify the developing applications in Rust using zkVM's such as SP1 or Risc0.

zkRust can be installed directly by downloading the latest release binaries:

```sh
curl -L https://raw.githubusercontent.com/yetanotherco/zkRust/main/install_zkrust.sh | bash
```

Then, to get started you can create a workspace for your project in zkRust by running:

```sh
cargo new <PROGRAM_DIRECTORY>
```

It is that simple.

## Usage

To use zkRust, users specify a `fn main()` whose execution is proven within the zkVM. This function must be defined in a `main.rs` file in a directory with the following structure:

```
.
└── <PROGRAM_DIRECTORY>
    ├── Cargo.toml
    └── src
        └── main.rs
```

For using more complex programs you can import a separate lib/ crate into the `PROGRAM_DIRECTORY`

```
.
└── <PROGRAM_DIRECTORY>
    ├── Cargo.toml
    ├── lib/
    └── src
        └── lib
```

### Inputs and Outputs

The user may also define a `input()` and `output()` functions in addition to `main()`, that define code that runs outside of the zkVM, before and after the VM executes

* The `input()` function executes before the zkVM code is executed and allows the user to define inputs passed to the vm such as a deserialized Tx or data fetched from an external source at runtime.
* Within the `main()` (guest) function the user may write information from the computation performed in the zkVM to an output buffer to be used after proof generation.
* The `output()` defines code that allows the user to read the information written to that buffer of the and perform post-processing of that data.

The user may specify inputs into the VM (guest) code using `zk_rust_io::write()` as long on the type of rust object they are writing implements `Serializable`.

Within the `main()` function (guest) the user may read in the inputs by specifying `zk_rust_io::read()` and output data computed during the execution phase of the code within the VM (guest) program by specifying `zk_rust_io::commit()`.

To read the output of the output of the VM (guest) program you declare `zk_rust_io::out()`. The `zk_rust_io` crate defines function headers that are not inlined and are purely used as compile time symbols to ensure a user can compile their rust code before running it within one of the zkVMs available in zkRust.

To use the I/O imports import the `zk_rust_io` crate by adding the following to the `Cargo.toml` in your project directory.

```sh
zk_rust_io = { git = "https://github.com/yetanotherco/zkRust.git", version = "v0.1.0" }
```

## Example

### input.rs

```rust
use zk_rust_io;

pub fn input() {
    let pattern = "a+".to_string();
    let target_string = "an era of truth, not trust".to_string();

    // Write in a simple regex pattern.
    zk_rust_io::write(&pattern);
    zk_rust_io::write(&target_string);
}
```

### main.rs

```rust
use regex::Regex;
use zk_rust_io;

pub fn main() {
    // Read two inputs from the prover: a regex pattern and a target string.
    let pattern: String = zk_rust_io::read();
    let target_string: String = zk_rust_io::read();

    // Try to compile the regex pattern. If it fails, write `false` as output and return.
    let regex = match Regex::new(&pattern) {
        Ok(regex) => regex,
        Err(_) => {
            panic!("Invalid regex pattern");
        }
    };

    // Perform the regex search on the target string.
    let result = regex.is_match(&target_string);

    // Write the result (true or false) to the output.
    zk_rust_io::commit(&result);
}
```

### output.rs

```rust
use zk_rust_io;

pub fn output() {
    // Read the output.
    let res: bool = zk_rust_io::out();
    println!("res: {}", res);
}
```

To generate a proof of the execution of your code run the following:

* **Sp1**:

```sh
  cargo run --release -- prove-sp1 <PROGRAM_DIRECTORY_PATH> .
```

* **Risc0**:

  ```sh
  cargo run --release -- prove-risc0  <PROGRAM_DIRECTORY_PATH> .
  ```

  Make sure to have [Risc0](https://dev.risczero.com/api/zkvm/quickstart#1-install-the-risc-zero-toolchain) installed with version `v3.0.3`. Running Risc0 on macOS enable [metal](https://developer.apple.com/metal/) acceleration by default and may need to be installed it needed.

For additional information on using zkRust and using it to submit proofs to Aligned see the [zkRust](https://github.com/yetanotherco/zkRust) Github Repository.


# Generating & submitting proofs of Rust code with ZKRust

[zkRust](https://github.com/yetanotherco/zkRust) is a CLI tool to generate proofs of your rust code using a RISCV-zkVM's and submit them to Aligned to be verified with only one command. The following provers are supported:

* [Risc0](https://github.com/risc0/risc0)
* [SP1](https://github.com/succinctlabs/sp1)

## Dependencies

To generate and submit proofs to Aligned using ZKRust, you need to have the following dependencies installed:

* [Rust](https://www.rust-lang.org/tools/install)
* [Foundry](https://book.getfoundry.sh/getting-started/installation) (**Optional**, needed only to create a local keystore to sign Ethereum transactions if you didn't already have one).

## Generate & Submit proofs

To generate and submit proofs to Aligned testnet using zkRust, you can follow the steps below:

### 1. Install zkRust :

The zkRust executable can be installed directly via the command line via:

```sh
curl -L https://raw.githubusercontent.com/yetanotherco/zkRust/main/install_zkrust.sh | bash
```

or built by cloning the repo

```sh
git clone https://github.com/yetanotherco/zkRust
cd zkRust
```

and running the installation script:

```sh
./install_aligned.sh
```

### 2. Generate a keystore:

{% hint style="warning" %}
When creating a new wallet keystore and private key please use strong passwords for your own protection.
{% endhint %}

You can use cast to create a local keystore. If you already have one, you can skip this step.

```bash
cast wallet new-mnemonic
```

Then you can import your created keystore using:

```bash
cast wallet import --interactive <path_to_keystore.json>
```

Make sure to send at least 0.1 Hoodi ETH to the address in the keystore. You can get Hoodi ETH from the [faucet](https://cloud.google.com/application/web3/faucet/ethereum/hoodi)

### 3. Generate and submit the proof with zkRust:

The zkRust repo has some predefined examples that can be used to generate a proof. You can find them in `zkRust/examples`. For example, to generate a proof of a `fibonacci` program with Risc0 or SP1 and submit it to aligned, run:

```sh
zkrust prove-risc0 \
    --submit-to-aligned \
    --keystore-path <PATH_TO_KEYSTORE> \
    examples/fibonacci
```

This command will generate a proof for the fibonacci example program and submit it to Aligned using the keystore provided for signing the transaction.

Take into consideration that the proof generation can take some time. Once the proof has been generated, a prompt will appear asking for the passphrase of your keystore and then send it to Aligned.

The same program can be proved using SP1 just changing the zkRust subcommand:

```bash
zkrust prove-sp1 \
    --submit-to-aligned \
    --keystore-path <PATH_TO_KEYSTORE> \
    examples/fibonacci
```

## Caveats

For the moment, the Rust code that can be proven has some limitations:

* Programs with user Input and Output to the vm code are not supported.


# Setup Aligned Infrastructure Locally

## Aligned Infrastructure Deployment Guide

### Dependencies

Ensure you have the following installed:

* [Go](https://go.dev/doc/install)
* [Rust](https://www.rust-lang.org/tools/install)
* [Foundry](https://book.getfoundry.sh/getting-started/installation)
* [jq](https://jqlang.github.io/jq/)
* [yq](https://github.com/mikefarah/yq)

After installing foundryup, you need to install a specific Foundry version:

```shell
foundryup -i v1.1.0
```

Then run:

```shell
make deps
```

This will:

* Initialize git submodules
* Install: `eigenlayer-cli`, `zap-pretty` and `abigen`
* Build ffis for your os.

### Contracts and eth node

To start anvil, a local Ethereum devnet with all necessary contracts already deployed and ready to be interacted with, run:

```shell
make anvil_start
```

<details>

<summary>More information on deploying the smart contracts on anvil:</summary>

#### EigenLayer Contracts

If EigenLayer contracts change, the anvil state needs to be updated with:

```bash
make anvil_deploy_eigen_contracts
```

This also deploys an ERC20 token with a strategy that can be used to test the EigenLayer restaking.

#### Aligned Contracts

When changing Aligned contracts, the anvil state needs to be updated with:

```bash
make anvil_deploy_aligned_contracts
```

Note that when changing the contracts, you must also re-generate the Go smart contract bindings:

```bash
make bindings
```

</details>

### Aggregator

To start the [Aggregator](/architecture/1_proof_verification_layer/5_aggregator):

```bash
make aggregator_start ENVIRONMENT=devnet
```

or with a custom config:

```bash
make aggregator_start ENVIRONMENT=devnet AGG_CONFIG_FILE=<path_to_config_file>
```

### Operator

To setup an [Operator](/architecture/1_proof_verification_layer/4_operator) run:

```bash
make operator_full_registration_and_start ENVIRONMENT=devnet
```

or with a custom config:

```bash
make operator_full_registration_and_start ENVIRONMENT=devnet CONFIG_FILE=<path_to_config_file>
```

Different configs for operators can be found in `config-files/config-operator`.

<details>

<summary>More information about Operator registration:</summary>

If you wish to only register an operator you can run:

```bash
make operator_full_registration CONFIG_FILE=<path_to_config_file>
```

and to start it once it has been registered:

```bash
make operator_start ENVIRONMENT=devnet CONFIG_FILE=<path_to_config_file>
```

</details>

### Batcher

To start the [Batcher](/architecture/1_proof_verification_layer/1_batcher) locally:

```bash
make batcher_start_local
```

This starts an [S3Mock](https://github.com/adobe/S3Mock) container to act as a replacement for S3.

If you want to use the batcher under a real `S3` connection you'll need to specify the environment variables under `crates/batcher/.env` and then run:

```bash
make batcher_start
```

***

## Other components

Aligned also counts with 2 external components, which are not necessary for Aligned to work, but are useful for observability.

### Explorer

#### Dependencies

Ensure you have the following installed:

* [Erlang 26](https://github.com/asdf-vm/asdf-erlang)
* [Elixir 1.16.2](https://elixir-ko.github.io/install.html), compiled with OTP 26
* [Docker](https://docs.docker.com/get-docker/)
* [NodeJS](https://nodejs.org/en/download/package-manager)
  * Tested with node 20 and 22
* [pnpm](https://pnpm.io/installation)

After installing the necessary deps, setup the environment variables by running:

```shell
make explorer_create_env
```

Then start the explorer:

```shell
make explorer_build_db
make explorer_start
```

This will:

* Start a postgres docker container
* Run ecto setup
* Start the explorer on <http://localhost:4000>.

<details>

<summary>Clean, dump and recover DB</summary>

To clear the DB, you can run:

```bash
make explorer_clean_db
```

If you need to dump the data from the DB, you can run:

```bash
make explorer_dump_db
```

This will create a `dump.$date.sql` SQL script on the `explorer` directory with all the existing data.

Data can be recovered from a `dump.$date.sql` using the following command:

```bash
make explorer_recover_db
```

Then you'll be requested to enter the file name of the dump you want to recover already positioned in the `/explorer` directory.

This will update your database with the dumped database data.

</details>

#### Fetching batches and operators data

If you want to fetch past batches that for any reason were not inserted into the DB, you will first need to make sure you have the `ELIXIR_HOSTNAME` in the `.env` file.

You can get the hostname of your elixir by running:

```bash
elixir -e 'IO.puts(:inet.gethostname() |> elem(1))'
```

Then you can run:

```bash
make explorer_fetch_old_batches FROM_BLOCK=<FROM_BLOCK> TO_BLOCK=<TO_BLOCK>
```

To get operators strategies and restakes data:

```bash
make explorer_fetch_old_operators_strategies_restakes FROM_BLOCK=<FROM_BLOCK>
```

### Metrics/Telemetry

The Metrics and Telemetry are used to view more in-depth information about the network. With it, you can visualize all sort of cumulative and historical metrics of the network, of the individual components and their behaviors. Tese services are not necessary to run aligned, though you will see warnings in the rest of components as they won't be able to connect and send their status.

#### Dependencies

Ensure you have the following installed:

* [Go](https://go.dev/doc/install)
* [Erlang 26](https://github.com/asdf-vm/asdf-erlang)
* [Elixir 1.16.2](https://elixir-ko.github.io/install.html), compiled with OTP 26
* [Docker](https://docs.docker.com/get-docker/)

#### Metrics service

To run Prometheus and Grafana, run:

```bash
make metrics_start
```

This will start containers for Prometheus and Grafana. You can access Grafana on `http://localhost:3000` with the default credentials `admin:admin`.

Alternately, you can access the raw scrapped metrics collected with Prometheus on `http://localhost:9091/metrics`.

#### Telemetry service

To setup the telemetry service run:

If it is your first time first you'll need to execute the following commands:

```bash
make telemetry_create_env
make telemetry_build_db
```

Then, to start the service:

```bash
make telemetry_start_all
```

This will:

* Start OpenTelemetry and Jaeger containers for the traces: available at `http://localhost:16686/`
* Start telemetry server: available at `http://localhost:4001/`

***

### Send test proofs

To send proofs quickly you can run any of the targets that have the prefix `batcher_send` for example:

Send a single plonk proof:

```shell
make batcher_send_plonk_bn254_task
```

Send a burst of `<N>` risc0 proofs:

```shell
make batcher_send_risc0_burst BURST_SIZE=<N>
```

Send an infinite stream of groth\_16 proofs:

```shell
make batcher_send_groth16_bn254_infinite BURST_SIZE=2
```

Feel free to explore the rest of targets.

***


# Setup Aligned Agg Mode Infrastructure Locally

## Dependencies

Ensure you have the following installed:

* [Rust](https://www.rust-lang.org/tools/install)
* [Docker](https://docs.docker.com/get-docker/)
* [Kurtosis](https://docs.kurtosis.com/install/)

## Supported Verifiers

The aggregation mode currently supports the following proving systems:

* **SP1** - Succinct's zkVM (compressed proofs)

## Step-by-Step Setup

Follow these steps to start the aggregation mode locally using the Ethereum package environment.

### 1. Start the Ethereum Package

Start the local Ethereum network using Kurtosis:

```bash
make ethereum_package_start
```

This command spins up a local Ethereum network with all necessary components. To stop it run:

```bash
make ethereum_package_rm
```

### 2. Start the Gateway

Start the aggregation mode gateway service:

```bash
make agg_mode_gateway_start_ethereum_package
```

The gateway handles proof submissions and manages the proof queue. This command also starts the required Docker containers (PostgreSQL) and runs database migrations automatically.

### 3. Start the Payments Poller

In a separate terminal, start the payments poller:

```bash
make agg_mode_payments_poller_start_ethereum_package
```

The payments poller monitors the blockchain for payment events and updates user quotas accordingly.

### 4. Send a Payment (Deposit)

Deposit funds to get quota for submitting proofs:

```bash
make agg_mode_gateway_send_payment
```

This deposits funds using a default test account. For custom deposits, you can use the CLI directly.

### 5. Submit a Proof

Submit an SP1 proof to the gateway:

```bash
make agg_mode_gateway_send_sp1_proof
```

This sends a test SP1 Fibonacci proof to the gateway.

### 6. Start the Proof Aggregator

In a separate terminal, start the proof aggregator:

```bash
AGGREGATOR=sp1 make proof_aggregator_start_ethereum_package
```

The proof aggregator fetches pending proofs from the database, aggregates them, and submits the aggregated proof on-chain.


# Contract Addresses

## Mainnet Deployments

### Verification Layer

| Contract                   | Address                                                                                                               |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| AlignedLayerServiceManager | [0xeF2A435e5EE44B2041100EF8cbC8ae035166606c](https://etherscan.io/address/0xeF2A435e5EE44B2041100EF8cbC8ae035166606c) |
| BlsApkRegistry             | [0x3CcfB7e6e8fe2A8d941a8Ce4C69A944a770E8228](https://etherscan.io/address/0x3CcfB7e6e8fe2A8d941a8Ce4C69A944a770E8228) |
| IndexRegistry              | [0x9Bf1275e18eC8FA3cA7f9bffF1b0DF3e14C6E134](https://etherscan.io/address/0x9Bf1275e18eC8FA3cA7f9bffF1b0DF3e14C6E134) |
| OperatorStateRetriever     | [0x6e0046205cAfA503F6b7465195A6C63C47d214f1](https://etherscan.io/address/0x6e0046205cAfA503F6b7465195A6C63C47d214f1) |
| RegistryCoordinator        | [0xA8CC0749b4409c3c47012323E625aEcBA92f64b9](https://etherscan.io/address/0xA8CC0749b4409c3c47012323E625aEcBA92f64b9) |
| StakeRegistry              | [0x45F5290a3630Cd6dc277B6f92227526121ca7c22](https://etherscan.io/address/0x45F5290a3630Cd6dc277B6f92227526121ca7c22) |
| BatcherPaymentService      | [0xb0567184A52cB40956df6333510d6eF35B89C8de](https://etherscan.io/address/0xb0567184A52cB40956df6333510d6eF35B89C8de) |

#### Strategies

Below is the list of supported strategies available on Aligned Mainnet:

| Name                                                       | Address                                                                                                               |
| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| [Beacon Chain ETH](https://app.eigenlayer.xyz/restake/ETH) | [0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0](https://etherscan.io/address/0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0) |
| [stETH](https://app.eigenlayer.xyz/restake/stETH)          | [0x93c4b944D05dfe6df7645A86cd2206016c51564D](https://etherscan.io/address/0x93c4b944D05dfe6df7645A86cd2206016c51564D) |
| [rETH](https://app.eigenlayer.xyz/restake/rETH)            | [0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2](https://etherscan.io/address/0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2) |
| [cbETH](https://app.eigenlayer.xyz/restake/cbETH)          | [0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc](https://etherscan.io/address/0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc) |
| [ETHx](https://app.eigenlayer.xyz/restake/ETHx)            | [0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d](https://etherscan.io/address/0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d) |
| [ankrETH](https://app.eigenlayer.xyz/restake/ankrETH)      | [0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff](https://etherscan.io/address/0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff) |
| [oETH](https://app.eigenlayer.xyz/restake/oETH)            | [0xa4C637e0F704745D182e4D38cAb7E7485321d059](https://etherscan.io/address/0xa4C637e0F704745D182e4D38cAb7E7485321d059) |
| [osETH](https://app.eigenlayer.xyz/restake/osETH)          | [0x57ba429517c3473B6d34CA9aCd56c0e735b94c02](https://etherscan.io/address/0x57ba429517c3473B6d34CA9aCd56c0e735b94c02) |
| [swETH](https://app.eigenlayer.xyz/restake/swETH)          | [0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6](https://etherscan.io/address/0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6) |
| [wBETH](https://app.eigenlayer.xyz/restake/wBETH)          | [0x7CA911E83dabf90C90dD3De5411a10F1A6112184](https://etherscan.io/address/0x7CA911E83dabf90C90dD3De5411a10F1A6112184) |
| [sfrxETH](https://app.eigenlayer.xyz/restake/sfrxETH)      | [0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6](https://etherscan.io/address/0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6) |
| [lsETH](https://app.eigenlayer.xyz/restake/lsETH)          | [0xAe60d8180437b5C34bB956822ac2710972584473](https://etherscan.io/address/0xAe60d8180437b5C34bB956822ac2710972584473) |
| [mETH](https://app.eigenlayer.xyz/restake/mETH)            | [0x298aFB19A105D59E74658C4C334Ff360BadE6dd2](https://etherscan.io/address/0x298aFB19A105D59E74658C4C334Ff360BadE6dd2) |

For additional details, refer to the [official EigenLayer documentation](https://github.com/Layr-Labs/eigenlayer-contracts).

### Aggregation Mode

| Contract                       | Address                                                                                                               |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| AlignedProofAggregationService | [0xD0696d3eEebffcAB2D1b358805efAA005A9A8BC0](https://etherscan.io/address/0xD0696d3eEebffcAB2D1b358805efAA005A9A8BC0) |
| AggregationModePaymentService  | [0xc8631Bc1E60c20db40e474F791126212fA8255F4](https://etherscan.io/address/0xc8631Bc1E60c20db40e474F791126212fA8255F4) |

## Hoodi Deployments

### Verification Layer

| Contract                       | Address                                                                                                                     |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| AlignedProofAggregationService | [0xEFeD2fd949995BE1a1C7f61AbFC0A33412c37f95](https://hoodi.etherscan.io/address/0xEFeD2fd949995BE1a1C7f61AbFC0A33412c37f95) |
| AlignedLayerServiceManager     | [0x87CD431F160e88EC34fA48EC6F6cF7F2C0E8248c](https://hoodi.etherscan.io/address/0x87CD431F160e88EC34fA48EC6F6cF7F2C0E8248c) |
| BlsApkRegistry                 | [0xa7Fc4D0Ad59593fB93B39c3353B4144Ea179f61e](https://hoodi.etherscan.io/address/0xa7Fc4D0Ad59593fB93B39c3353B4144Ea179f61e) |
| IndexRegistry                  | [0x85e972915Ca1FeDF6Ad8361cC1F78211bd3cA6a1](https://hoodi.etherscan.io/address/0x85e972915Ca1FeDF6Ad8361cC1F78211bd3cA6a1) |
| OperatorStateRetriever         | [0x9B0062e85c7d5f7c195b7Ef351A377dd81e9E055](https://hoodi.etherscan.io/address/0x9B0062e85c7d5f7c195b7Ef351A377dd81e9E055) |
| RegistryCoordinator            | [0xD06AAf23d136ECBfb5Bdb349Dd7a87aDc74673Dd](https://hoodi.etherscan.io/address/0xD06AAf23d136ECBfb5Bdb349Dd7a87aDc74673Dd) |
| StakeRegistry                  | [0xCe3DFA29Ce371ccE673E631213d827157cfe67e0](https://hoodi.etherscan.io/address/0xCe3DFA29Ce371ccE673E631213d827157cfe67e0) |
| BatcherPaymentService          | [0x041af25Fce2413570aaa0029D36DeA1eFdeff083](https://hoodi.etherscan.io/address/0x041af25Fce2413570aaa0029D36DeA1eFdeff083) |

#### Strategies

Below is the list of supported strategies available on Aligned Hoodi:

| Name                                                       | Address                                                                                                                     |
| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| [Beacon Chain ETH](https://hoodi.eigenlayer.xyz/token/ETH) | [0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0](https://hoodi.etherscan.io/address/0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0) |
| [stETH](https://hoodi.eigenlayer.xyz/token/stETH)          | [0x19536FAd6Eb831e8211B316177979161BBdb2c2B](https://hoodi.etherscan.io/address/0x19536FAd6Eb831e8211B316177979161BBdb2c2B) |
| [WETH](https://hoodi.eigenlayer.xyz/token/WETH)            | [0x24579aD4fe83aC53546E5c2D3dF5F85D6383420d](https://hoodi.etherscan.io/address/0x24579aD4fe83aC53546E5c2D3dF5F85D6383420d) |

### Aggregation Mode

| Contract                       | Address                                                                                                                     |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| AlignedProofAggregationService | [0x6B34AAaE780A5EAB4c91AB8F54f2a421E9c2FB59](https://hoodi.etherscan.io/address/0x6B34AAaE780A5EAB4c91AB8F54f2a421E9c2FB59) |
| AggregationModePaymentService  | [0xe6C9D0cf87cdaA8B2093c4b3830dde7267843F64](https://hoodi.etherscan.io/address/0xe6C9D0cf87cdaA8B2093c4b3830dde7267843F64) |

## Sepolia Deployments

### Verification Layer

| Contract                   | Address                                                                                                                       |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| AlignedLayerServiceManager | [0xFf731AB7b3653dc66878DC77E851D174f472d137](https://sepolia.etherscan.io/address/0xFf731AB7b3653dc66878DC77E851D174f472d137) |
| BlsApkRegistry             | [0x33b541E0C2725eEa4FB61F5f0E40ef84e764A228](https://sepolia.etherscan.io/address/0x33b541E0C2725eEa4FB61F5f0E40ef84e764A228) |
| IndexRegistry              | [0xA5EA732c82f51Bcbff4021c1F6EA3853B6565347](https://sepolia.etherscan.io/address/0xA5EA732c82f51Bcbff4021c1F6EA3853B6565347) |
| OperatorStateRetriever     | [0xE4BDE5A267a44444E2808c60B4Abf89e74f552c6](https://sepolia.etherscan.io/address/0xE4BDE5A267a44444E2808c60B4Abf89e74f552c6) |
| RegistryCoordinator        | [0x0Ef1920F089DD02d3A28BF2e34342FD3e74160A3](https://sepolia.etherscan.io/address/0x0Ef1920F089DD02d3A28BF2e34342FD3e74160A3) |
| StakeRegistry              | [0xe87cB8f9C74264BD446835F899e15c3AE1209C34](https://sepolia.etherscan.io/address/0xe87cB8f9C74264BD446835F899e15c3AE1209C34) |
| BatcherPaymentService      | [0x403dE630751e148bD71BFFcE762E5667C0825399](https://sepolia.etherscan.io/address/0x403dE630751e148bD71BFFcE762E5667C0825399) |

### Aggregation Mode

| Contract                       | Address                                                                                                                       |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| AlignedProofAggregationService | [0xb5D46304c30B1AeB3a8Da6ab599c336f7946C8A4](https://sepolia.etherscan.io/address/0xb5D46304c30B1AeB3a8Da6ab599c336f7946C8A4) |


# Submitting Batch Without Batcher

Aligned's infrastructure contains a key element, the [Batcher](/architecture/1_proof_verification_layer/1_batcher), which bundles many proofs together to reduce the cost of both submission and verification for each proof.

However, the Batcher is not 100% necessary for a User to submit proofs to Aligned. This is because, as you may have realized, any account can call `createNewTask(bytes32 batchMerkleRoot, string batchDataPointer)` in [Aligned Service Manager Contract](/architecture/1_proof_verification_layer/3_service_manager_contract). This means any Ethereum account can create a new task, as long as it supplies a pointer to where the proofs or the batch can be found, and its merkle root.

## Why would I want to submit a batch without using the Batcher?

The answer lies on each User. It may be because:

* A User does not want to share its batch with another User's proofs.
* A User submitter wants to keep sovereignty over the location and storage of its proofs. (Aligned's Batcher stores them on an AWS S3 bucket in the us-east-2 region)
* A User wants to change the lifetime content of his proofs. (Aligned Batcher stores them for 7 days).

## Tradeoffs

As the Batcher bundles proofs together, it reduces the cost for each proof. A User who doesn't want to use the Batcher will need to accumulate a large quantity of proofs. Otherwise, they will end up paying more per proof. The User must make sure his account has enough funds in the Aligned Service Manager Contract, or his batches submissions or responses could fail for lack of funds.

The User should run a pre-verification to make sure he is not wasting funds in submitting a false proof.

## How-to

If, after this analysis, a User still wants to submit his own Batch, here is how:

1. Collect the proof/s he wants to submit to Aligned, build a merkle tree with them and calculate their merkle root.
2. Upload the proofs to any publicly accessible S3-compatible form of storage, in CBOR serialization format, following the following structure:

   ```
   [
       {
           "proving_system": "GnarkGroth16Bn254",
           "proof": [
               152, 88, 141, 155, 88, 35, 94, 76, ...
           ],
           "verification_key": [
               199, 79, 8, 204, 10, 130, 85, 150, ...
           ],
           "vm_program_code": null,
           "proof_generator_addr": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
       },
       ...
   ]
   ```

   Note: If it is not publicly accessible, if it is not S3-compatible, or if it does not follow the correct batch structure, operators will not be able to download the proofs to verify them.
3. Call `createNewTask(bytes32 batchMerkleRoot, string batchDataPointer)` on the Aligned Service Manager Contract, from a funded Batcher account.
   * To fund a Batcher account, you must either send funds to the Aligned Service Manager Contract beforehand, or you can send funds within the same `createNewTask` function call.
   * `bytes32 batchMerkleRoot` must be the Merkle Root, in format bytes32, of the tree generated with the submitted proofs. If the Operators find the Merkle Root does not correspond to the downloaded batch, they will not verify the proofs.
   * `string batchDataPointer` must be a string containing the pointer (link, url, etc.) to where the proofs are stored.
4. After `createNewTask` is correctly executed, it will emit Events for the other components of Aligned. The Batch has been submitted.


# Verification Layer CLI

The Aligned CLI serves as an interface for users to interact with Aligned Layer.

This document serves as a reference for the commands of the Aligned CLI.

## Installation:

1. Download and install Aligned from the Aligned GitHub repo `https://github.com/yetanotherco/aligned_layer`:

   ```bash
   curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/main/crates/cli/install_aligned.sh | bash
   ```
2. A source command will be printed in your terminal after installation. Execute that command to update your shell environment.
3. Verify that the installation was successful:

   ```bash
   aligned --version
   ```

## Help:

To see the available commands, run:

```bash
aligned --help
```

To see the usage of a command, run:

```bash
aligned [COMMAND] --help
```

## CLI Commands

### **submit**

#### Description:

Submit a proof to the Aligned Layer batcher.

#### Command:

`submit [OPTIONS] --proving_system <proving_system> --proof <proof_file_path>`

#### Options:

* `--batcher_url <batcher_connection_address>`: Websocket URL for the Aligned Layer batcher
  * Default: `ws://localhost:8080`
  * Mainnet: `wss://mainnet.batcher.alignedlayer.com`
  * Sepolia: `wss://sepolia.batcher.alignedlayer.com`
  * Hoodi: `wss://hoodi.batcher.alignedlayer.com`
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* `--proving_system <proving_system>`: Proof system of the submitted proof
  * Possible values: `GnarkPlonkBls12_381`, `GnarkPlonkBn254`, `Groth16Bn254`, `SP1`, `Risc0`, `CircomGroth16Bn256`
* `--proof <proof_file_path>`: Path to the proof file.
* `--public_input <public_input_file_path>`: Path to the public input file.
* `--vk <verification_key_file_path>`: Path to the verification key file (required for specific proof systems).
* `--vm_program <vm_program_code_file_path>`: Path to the VM program code file (required for some specific proof systems).
* `--repetitions <n>`: Number of repetitions of the proof submission.
  * Default: `1`
* `--proof_generator_addr <proof_generator_address>`: Proof generator address.
  * Default: `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` (Anvil prefunded account 0)
* `--aligned_verification_data_path <aligned_verification_data_directory_path>`: Directory for aligned verification data.
  * Default: `./aligned_verification_data/`
* `--keystore_path <path_to_local_keystore>`: Path to the local keystore.
* `--private_key <private_key>`: User's wallet private key.
* `--nonce <n>`: Proof nonce.
  * By default, the nonce is set automatically. By setting the nonce manually, you can perform a proof replacement. To perform a valid replacement, the new proof must have a max\_fee 10% higher than the previous one.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`
* Max Fee allowed to be spent for each proof verification, use one of the following:
  * `--max_fee <max_fee (ether)>`: Specifies a `max_fee` in Ether.
  * `--default_fee_estimate`: Specifies a `max_fee` equivalent to the cost of 1 proof in a batch of size 10.
  * `--instant_fee_estimate`: Specifies a `max_fee` that ensures the proof is included instantly, equivalent to the cost of a proof in a batch of size 1.
  * `--custom_fee_estimate <amount_of_proofs_in_batch>`: Specifies a `max_fee` equivalent to the cost of 1 proof in a batch of size `num_proofs_in_batch`.
* `random_address`: If set, random addresses will be used as `proof_generator_addr` for each proof.
  * Default: `false`

#### Example:

```bash
aligned submit  \
--proving_system Risc0 \
--proof ./scripts/test_files/risc_zero/fibonacci_proof_generator/risc_zero_fibonacci_3_0_3.proof \
--vm_program ./scripts/test_files/risc_zero/fibonacci_proof_generator/fibonacci_id_3_0_3.bin \
--public_input ./scripts/test_files/risc_zero/fibonacci_proof_generator/risc_zero_fibonacci_3_0_3.pub \
--repetitions <BURST_SIZE> \
--keystore_path <KEYSTORE_PATH> \
--batcher_url wss://batcher.alignedlayer.com \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--max_fee 0.0013ether
```

***

### **verify-proof-onchain**

#### Description:

Check if a proof was verified by Aligned on Ethereum.

#### Command:

`verify-proof-onchain [OPTIONS] --aligned-verification-data <aligned_verification_data>`

#### Options:

* `--aligned-verification-data <aligned_verification_data>`: Path to the aligned verification data file.
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`

#### Example:

```bash
aligned verify-proof-onchain \
--aligned-verification-data ./aligned_verification_data/<VERIFICATION_DATA_FILE> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

***

### **get-vk-commitment**

#### Description:

Computes the verification data commitment from the verification data file.

#### Command:

`get-vk-commitment [OPTIONS] --verification_key_file <verification_key_file_path> --proving_system <proving_system>`

#### Options:

* `--verification_key_file <path_to_file>`: Path to the verification key file.
* `--proving_system <proving_system>`: Proof system of the verification data file.
  * Possible values: `GnarkPlonkBls12_381`, `GnarkPlonkBn254`, `Groth16Bn254`, `SP1`, `Risc0`
* `--output <path_to_file>`: File path to write the output.

***

### **deposit-to-batcher**

#### Description:

Deposits Ethereum into the Aligned Layer's `BatcherPaymentService.sol` contract.

#### Command:

`deposit-to-batcher [OPTIONS] --keystore_path <path_to_local_keystore> --amount <amount_to_deposit>`

#### Options:

* `--keystore_path <path_to_local_keystore>`: Path to the local keystore.
* `--private_key <private_key>`: User's wallet private key.
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* `--amount <amount (ether)>`: Amount of Ether to deposit.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`

#### Example:

```bash
aligned deposit-to-batcher \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--amount 0.5ether \
--keystore_path <KEYSTORE_PATH>
```

***

### **get-user-balance**

#### Description:

Retrieves the user's balance in the Aligned Layer's contract.

#### Command:

`get-user-balance [OPTIONS] --user_addr <user_ethereum_address>`

#### Options:

* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* `--user_addr`: User's Ethereum address.

#### Example:

```bash
aligned get-user-balance \
--user_addr <WALLET_ADDRESS> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

***

### **get-user-nonce**

#### Description:

Retrieves the user's current nonce from the Batcher.

#### Command:

`get-user-nonce [OPTIONS] --user_addr <user_ethereum_address>`

#### Options:

* `--user_addr <user_address>`: User's Ethereum address.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`

#### Example:

```bash
aligned get-user-nonce \
--user_addr <USER_ETH_ADDRESS> \
--network hoodi
```

***

### **get-user-nonce-from-ethereum**

#### Description:

Retrieves the user's current nonce from the Blockhain, in the Batcher Payment Service Contract.

#### Command:

`get-user-nonce-from-ethereum [OPTIONS] --user_addr <user_ethereum_address>`

#### Options:

* `--user_addr <user_address>`: User's Ethereum address.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.

#### Example:

```bash
aligned get-user-nonce-from-ethereum \
--user_addr <USER_ETH_ADDRESS> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

***

### **get-user-last-max-fee**

#### Description:

Retrieves the `max_fee` of the proof with the highest nonce in the batcher queue for a given address.

This value represents the maximum fee limit that can be used when submitting the next proof. To increase the fee limit for a new proof, you must first bump the fee of the previous proofs queued in the batcher.

Read more here: <https://docs.alignedlayer.com/architecture/1\\_proof\\_verification\\_layer/1\\_batcher#max-fee-priority-queue>

#### Command:

`get-user-last-max-fee [OPTIONS] <user_ethereum_address>`

#### Options:

* `<user_ethereum_address>`: User's Ethereum address.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`

#### Example:

```bash
aligned get-user-last-max-fee \
<USER_ETH_ADDRESS> \
--network hoodi
```

#### Notes:

* Returns `U256::MAX` (2^256 - 1) when no proofs are present in the queue for the user.

***

### **get-user-amount-of-queued-proofs**

#### Description:

Retrieves the number of proofs currently queued for a given user in the Batcher.

#### Command:

`get-user-amount-of-queued-proofs [OPTIONS] --user_addr <user_ethereum_address>`

#### Options:

* `--user_addr <user_address>`: User's Ethereum address.
* Specify which network to interact with, using one of the following options:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom network, instead of `--network`, provide the following flags:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`: Address of the Aligned Service Manager contract.
    * `--batcher_payment_service <batcher_payment_service_contract_address>`: Address of the Batcher Payment Service contract.
    * `--batcher_url <batcher_websocket_url>`: WebSocket URL for the Aligned batcher.
* `--rpc_url <rpc_provider_url>`: Ethereum RPC provider URL.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * You can also specify your own RPC provider URL

#### Example:

```bash
aligned get-user-amount-of-queued-proofs  \
--user_addr <USER_ETH_ADDRESS> \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com
```

***

### **lock-funds**

#### Description:

Locks funds in the batcher. Locked balances can be used for proof verification payments but cannot be withdrawn until they are unlocked and the lock period expires.

#### Command:

`lock-funds [OPTIONS]`

#### Options:

* `--keystore_path <path_to_local_keystore>`: Path to the local keystore.
* `--private_key <private_key>`: User's wallet private key.
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`

#### Example:

```bash
aligned lock-funds \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--keystore_path <KEYSTORE_PATH>
```

***

### **unlock-funds**

#### Description:

Unlocks funds from the batcher. After calling this command, users must wait for the lock period before they can withdraw their funds using `withdraw-funds`.

#### Command:

`unlock-funds [OPTIONS]`

#### Options:

* `--keystore_path <path_to_local_keystore>`: Path to the local keystore.
* `--private_key <private_key>`: User's wallet private key.
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`

#### Example:

```bash
aligned unlock-funds \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--keystore_path <KEYSTORE_PATH>
```

***

### **withdraw-funds**

#### Description:

Withdraws a specified amount from the user's balance in the batcher. This command can only be used after the balance has been unlocked using `unlock-funds` and the lock period has expired.

#### Command:

`withdraw-funds [OPTIONS] --amount <amount_to_withdraw>`

#### Options:

* `--keystore_path <path_to_local_keystore>`: Path to the local keystore.
* `--private_key <private_key>`: User's wallet private key.
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* `--amount <amount (ether)>`: Amount of Ether to withdraw.
* One of the following, to specify which Network to interact with:
  * `--network <working_network_name>`: Network name to interact with.
    * Default: `devnet`
    * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
  * For a custom Network, you must specify the following parameters:
    * `--aligned_service_manager <aligned_service_manager_contract_address>`
    * `--batcher_payment_service <batcher_payment_service_contract_address>`
    * `--batcher_url <batcher_websocket_url>`

#### Example:

```bash
aligned withdraw-funds \
--network hoodi \
--rpc_url https://ethereum-hoodi-rpc.publicnode.com \
--amount 0.5ether \
--keystore_path <KEYSTORE_PATH>
```

***

### **verify-agg-proof**

#### Description:

Verifies if your proof has been verified by the `Aggregation Mode`.

#### Command:

`aligned verify-agg-proof [OPTIONS] --proving_system <proving_system>`

#### Options:

* `--vk`: Verification key hash file path.
* `--public_input`: Your program committed values file path.
* `--from-block`: From which block to start fetching events. This must no be older than 18 days as blobs will be expired. Defaults to the block corresponding to last 24 hours.
* `--network <working_network_name>`: Network name to interact with.
  * Default: `devnet`
  * Possible values: `devnet`, `sepolia`, `mainnet`, `hoodi`
* `--rpc_url <RPC_provider_url>`: User's Ethereum RPC provider connection address.
  * Default: `http://localhost:8545`
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Sepolia: `https://ethereum-sepolia-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`
  * Also, you can use your own Ethereum RPC providers.
* `--beacon_client_url <BEACON_CLIENT_URL>`: User's Ethereum Consensus provider connection address. Public nodes don't support this method.

#### Example:

```bash
aligned verify-agg-proof \
  --network hoodi \
  --from-block 3638552 \
  --proving_system SP1 \
  --public_input ../../scripts/test_files/sp1/sp1_fibonacci_5_0_0.pub \
  --vk ./scripts/test_files/sp1/sp1_fibonacci_5_0_0.vk \
  --beacon_url <YOUR_BEACON_CLIENT> \
  --rpc_url https://ethereum-hoodi-rpc.publicnode.com
```


# Aggregation Mode CLI

The Aggregation Mode CLI serves as an interface for users to interact with Aligned Aggregation Mode.

This document serves as a reference for the commands of the Aggregation Mode CLI.

> **Note:** Aggregation Mode is currently available on the [`staging` branch](https://github.com/yetanotherco/aligned_layer/tree/staging).

## Installation

1. Clone the Aligned Layer repository:

   ```bash
   git clone https://github.com/yetanotherco/aligned_layer.git
   cd aligned_layer
   git checkout staging
   ```
2. Build and install the Aggregation Mode CLI using the Makefile:

   ```bash
   make agg_mode_install_cli
   ```
3. Verify that the installation was successful:

   ```bash
   agg-mode-cli --version
   ```

> **Note:** A standalone installation script will be available soon for easier installation without cloning the repository.

## Help

To see the available commands, run:

```bash
agg_mode_cli --help
```

To see the usage of a command, run:

```bash
agg_mode_cli [COMMAND] --help
```

## CLI Commands

### **deposit**

#### Description

Send ether to the Aggregation Mode payment service to fund your proof submission quota.

#### Command

`deposit [OPTIONS] --rpc-url <rpc_url>`

#### Options

* `--keystore-path <keystore_path>`: Path to the local keystore file.
* `--private-key <private_key>`: User's wallet private key.
  * Note: Either `--keystore-path` or `--private-key` must be provided, but not both.
* `-n, --network <network>`: Network to interact with.
  * Default: `devnet`
  * Possible values: `devnet`, `hoodi`, `mainnet`
* `--rpc-url <rpc_url>`: Ethereum RPC provider URL.
  * Mainnet: `https://ethereum-rpc.publicnode.com`
  * Hoodi: `https://ethereum-hoodi-rpc.publicnode.com`

#### Example

```bash
agg_mode_cli deposit \
  --keystore-path ~/.ethereum/keystore/my-key.json \
  --network hoodi \
  --rpc-url https://ethereum-hoodi-rpc.publicnode.com
```

***

### **submit sp1**

#### Description

Submit an SP1 proof to the Aggregation Mode Gateway for verification.

#### Command

`submit sp1 [OPTIONS] --proof <proof_path> --vk <verifying_key_path>`

#### Options

* `-p, --proof <proof_path>`: Path to the SP1 proof file (bincode serialized).
* `--vk <verifying_key_path>`: Path to the SP1 verifying key file (bincode serialized).
* `--keystore-path <keystore_path>`: Path to the local keystore file.
* `--private-key <private_key>`: User's wallet private key.
  * Note: Either `--keystore-path` or `--private-key` must be provided, but not both.
* `-n, --network <network>`: Network to interact with.
  * Default: `devnet`
  * Possible values: `devnet`, `hoodi`, `mainnet`

#### Example

```bash
agg_mode_cli submit sp1 \
  --proof ./my_proof.bin \
  --vk ./my_vk.bin \
  --keystore-path ~/.ethereum/keystore/my-key.json \
  --network hoodi
```

#### Notes

* The proof will be aggregated and settled to L1 within the configured aggregation window (default: 24 hours).
* A task ID is returned upon successful submission, which can be used to track the proof status.

***

### **verify-on-chain**

#### Description

Check whether a proof has been verified on the AlignedProofAggregationService contract.

#### Command

`verify-on-chain [OPTIONS] --rpc-url <rpc_url> --beacon-url <beacon_url> --proving-system <proving_system> --vk-hash <vk_hash_path>`

#### Options

* `-n, --network <network>`: Network to interact with.
  * Default: `devnet`
  * Possible values: `devnet`, `hoodi`, `mainnet`
* `--rpc-url <rpc_url>`: Ethereum RPC provider URL.
* `--beacon-url <beacon_url>`: Beacon chain client URL.
* `--from-block <block_number>`: Block number to start searching from.
  * Default: Current block minus 7500 blocks (\~25 hours)
* `--proving-system <proving_system>`: The proving system used.
  * Possible values: `SP1`, `Risc0`
* `--vk-hash <vk_hash_path>`: Path to the file containing the program verification key hash (32 bytes).
* `--public-inputs <public_inputs_path>`: Path to the public inputs file.

#### Example

```bash
agg-mode-cli verify-on-chain \
  --network hoodi \
  --rpc-url https://ethereum-hoodi-rpc.publicnode.com \
  --beacon-url https://ethereum-hoodi-beacon-api.publicnode.com \
  --proving-system SP1 \
  --vk-hash ./my_vk_hash.bin \
  --public-inputs ./my_public_inputs.bin
```

#### Notes

* If your proof isn't found, try specifying an earlier `--from-block` to search further back in history.
* The command verifies the proof's inclusion in the Merkle tree of the aggregated batch.


# Running an operator

> **CURRENT VERSION:** Aligned Operator [v0.20.0](https://github.com/yetanotherco/aligned_layer/releases/tag/v0.20.0)

> **IMPORTANT:** You must be [whitelisted](https://docs.google.com/forms/d/e/1FAIpQLSdH9sgfTz4v33lAvwj6BvYJGAeIshQia3FXz36PFfF-WQAWEQ/viewform) to become an Aligned operator.

## Requirements

This guide assumes you are already [registered as an operator with EigenLayer](https://docs.eigencloud.xyz/products/eigenlayer/operators/howto/operator-installation).

## Hardware Requirements

Minimum hardware requirements:

| Component     | Specification     |
| ------------- | ----------------- |
| **CPU**       | 16 cores          |
| **Memory**    | 32 GB RAM         |
| **Bandwidth** | 1 Gbps            |
| **Storage**   | 256 GB disk space |

## Supported Strategies

The list of supported strategies can be found [here](https://github.com/yetanotherco/aligned_layer/blob/testnet/docs/3_guides/7_contract_addresses.md).

## Step 1 - Clone the repo

To start with, clone the Aligned repository and move inside it

```bash
git clone https://github.com/yetanotherco/aligned_layer.git --branch v0.20.0
cd aligned_layer
```

## Step 2 - Building the Operator

Ensure you have the following installed:

* [Go](https://go.dev/doc/install)
* [Rust](https://www.rust-lang.org/tools/install)
* [Foundry](https://book.getfoundry.sh/getting-started/installation)

Also, you have to install the following dependencies for Linux:

* pkg-config
* libssl-dev
* g++

To install foundry, run:

```bash
make foundry_install
foundryup
```

To build the operator binary for **Hoodi** or **Sepolia**, run:

```bash
make operator_build ENVIRONMENT=testnet
```

To build the operator binary for **Mainnet**, run:

```bash
make operator_build ENVIRONMENT=mainnet
```

### Upgrading the Operator

If you want to upgrade the operator in **Hoodi** or **Sepolia**, run:

```bash
make operator_update ENVIRONMENT=testnet
```

If you want to upgrade the operator in **Mainnet**, run:

```bash
make operator_update ENVIRONMENT=mainnet
```

This will recreate the binaries. You can then proceed to restart the operator.

You can find the latest version of the operator [here](https://github.com/yetanotherco/aligned_layer/releases).

### Checking the Operator Version

To see the operator version, run:

```bash
./operator/build/aligned-operator --version
```

This will display the current version of the operator binary.

## Step 3 - Update the configuration for your specific Operator

Locate the appropiate `operator_config_file`:

* Mainnet: `./config-files/config-operator-mainnet.yaml`.
* Sepolia: `./config-files/config-operator-sepolia.yaml`.
* Hoodi: `./config-files/config-operator-hoodi.yaml`.

Update the following placeholders:

* `"<operator_address>"`
* `"<earnings_receiver_address>"`
* `"<ecdsa_key_store_location_path>"`
* `"<ecdsa_key_store_password>"`
* `"<bls_key_store_location_path>"`
* `"<bls_key_store_password>"`

`"<ecdsa_key_store_location_path>"` and `"<bls_key_store_location_path>"` are the paths to your keys generated with the EigenLayer CLI, `"<operator_address>"` and `"<earnings_receiver_address>"` can be found in the `operator.yaml` file created in the EigenLayer registration process.

The keys are stored by default in the `~/.eigenlayer/operator_keys/` directory, so for example `<ecdsa_key_store_location_path>` could be `/path/to/home/.eigenlayer/operator_keys/some_key.ecdsa.key.json` and for `<bls_key_store_location_path>` it could be `/path/to/home/.eigenlayer/operator_keys/some_key.bls.key.json`.

{% hint style="danger" %}
Don't keep the Operator Key in the Aligned Operator Node. If you already registered, don't use it. If you need to register, delete it after step 4.
{% endhint %}

The ECDSA key is only used for registration and funding of the operator and is not needed afterwards. It is recommended that you remove it after you're done, as well as the `ecdsa` section in the config file, or better yet for that data to never make it to the server (e.g., you run the registration from a machine without listening ports).\
If you run the registration on the server, it's recommended to do this part on a RAM filesystem to ease secure removal, and only after removing the `ecdsa` section move the config file to persistent storage.

If you run on a different computer, you will need to copy the BLS key store to the server.

Two RPCs are used, one as the main one, and the other one as a fallback in case one node is working unreliably.

Default configurations is set up to use the same public node in both scenarios.

{% hint style="danger" %}
PUBLIC NODES SHOULDN'T BE USED AS THE MAIN RPC. We recommend not using public nodes at all.

FALLBACK AND MAIN RPCs SHOULD BE DIFFERENT.
{% endhint %}

Most of the actions will pass through the main RPC unless there is a problem with it. Events are fetched from both nodes.

```yaml
eth_rpc_url: "https://<RPC_1>" 
eth_rpc_url_fallback: "https://<RPC_2>"
eth_ws_url: "wss://<RPC_1>"
eth_ws_url_fallback: "wss://<RPC_2>"
```

## Step 4 - Register Operator on AlignedLayer

Then you must register as an Operator on AlignedLayer. To do this, you must run:

* Mainnet:

  ```bash
  make operator_register_with_aligned_layer CONFIG_FILE=./config-files/config-operator-mainnet.yaml
  ```
* Sepolia:

  ```bash
  make operator_register_with_aligned_layer CONFIG_FILE=./config-files/config-operator-sepolia.yaml
  ```
* Hoodi:

  ```bash
  make operator_register_with_aligned_layer CONFIG_FILE=./config-files/config-operator-hoodi.yaml
  ```

{% hint style="danger" %}
If you are going to run the server in this machine, delete the operator key
{% endhint %}

## Step 5 - Start the operator

* Mainnet:

  ```bash
  ./operator/build/aligned-operator start --config ./config-files/config-operator-mainnet.yaml
  ```
* Sepolia:

  ```bash
  ./operator/build/aligned-operator start --config ./config-files/config-operator-sepolia.yaml
  ```
* Hoodi:

  ```bash
  ./operator/build/aligned-operator start --config ./config-files/config-operator-hoodi.yaml
  ```

### Run Operator using Systemd

To manage the Operator process on Linux systems, we recommend use systemd with the following configuration:

You should create a user and a group in order to run the Operator and set the service unit to use that. In the provided service unit, we assume you have already created a user called `aligned`

```toml
# aligned-operator.service

[Unit]
Description=Aligned Operator
After=network.target

[Service]
Type=simple
User=aligned
ExecStart=<path_to_aligned_layer_repository>/operator/build/aligned-operator start --config <path_to_operator_config_file>
Restart=always
RestartSec=1
StartLimitBurst=100

[Install]
WantedBy=multi-user.target
```

{% hint style="info" %}
`aligned-operator.service` is just an arbitrary name. You can name your service as you wish, following the format `<service-name>.service`.
{% endhint %}

Once you have configured the `aligned-operator.service` file, you need to run the following commands:

```shell
sudo cp aligned-operator.service /etc/systemd/system/aligned-operator.service
sudo systemctl enable --now aligned-operator.service
```

{% hint style="warning" %}
All paths must be absolute.
{% endhint %}

Those commands will link the service to systemd directory and then, will start the Operator service.

Also, if the server running the operator goes down, systemd will start automatically the Operator on server startup.

#### Restart operator

If you want to restart the operator, you can use the following command:

```shell
sudo systemctl restart aligned-operator.service
```

#### Get Operators logs

Once you are running your operator using systemd, you can get its logs using journalctl as follows:

```shell
journalctl -xfeu aligned-operator.service
```

## Operator Metrics

Metrics are exposed by default at `localhost:9092/metrics` in Prometheus format. To change the endpoint, update the following line in the configuration file:

```yaml
metrics_ip_port_address: localhost:9092
```

Example of exposed metrics:

```yaml
# HELP aligned_operator_responses_count Number of proof verified by the operator and sent to the Aligned Service Manager
# TYPE aligned_operator_responses_count counter
aligned_operator_responses_count x
```

You can scrape these metrics using Prometheus and visualize them in Grafana or configure alerts based on the data.

## Unregistering the operator

To unregister the Aligned operator, run:

* Mainnet:

  ```bash
  cast send --rpc-url https://ethereum-rpc.publicnode.com --private-key <private_key> 0xA8CC0749b4409c3c47012323E625aEcBA92f64b9 'deregisterOperator(bytes)' 0x00
  ```
* Sepolia:

  ```bash
  cast send --rpc-url https://ethereum-sepolia-rpc.publicnode.com --private-key <private_key> 0x0Ef1920F089DD02d3A28BF2e34342FD3e74160A3 'deregisterOperator(bytes)' 0x00
  ```
* Hoodi:

  ```bash
  cast send --rpc-url https://ethereum-hoodi-rpc.publicnode.com --private-key <private_key> 0xD06AAf23d136ECBfb5Bdb349Dd7a87aDc74673Dd 'deregisterOperator(bytes)' 0x00
  ```

`<private_key>` is the one specified in the output when generating your keys with the EigenLayer CLI.

## Deposit Strategy Tokens in Hoodi

You can restake [stETH](https://hoodi.eigenlayer.xyz/token/stETH) as the strategy token.

You will need to stake a minimum of 1000 WEI in stETH. We recommend to stake a maximum amount of 10 stETH. If you are staking more than 10 stETH please unstake any surplus over 10.

If you already have ETH and need to convert it to stETH, you can get it from [Lido Website](https://stake-hoodi.testnet.fi/).

Finally, to end the staking process, you need to deposit into the stETH strategy,

There are two options, either doing it through EigenLayer's website, or running the commands specified by us below.

### Option 1

To restake through EigenLayer's website, go to [stETH strategy](https://hoodi.eigenlayer.xyz/token/stETH).

### Option 2

To deposit one stETH using the Operator CLI, run the following command:

```bash
./operator/build/aligned-operator deposit-into-strategy --config ./config-files/config-operator.yaml --strategy-address 0x19536FAd6Eb831e8211B316177979161BBdb2c2B --amount 1000000000000000000
```

Where [`0x19536FAd6Eb831e8211B316177979161BBdb2c2B`](https://hoodi.etherscan.io/address/0x19536FAd6Eb831e8211B316177979161BBdb2c2B) is the stETH strategy address in Hoodi.

If you don't have Hoodi ETH, these are some useful faucets:

* [Hoodi Faucet](https://cloud.google.com/application/web3/faucet/ethereum/hoodi)


# Operator FAQ

The EigenLayer Operator installation guide is available [here](https://docs.eigencloud.xyz/products/eigenlayer/operators/howto/operator-installation).

### How do I get whitelisted to run an operator?

To get whitelisted, you need to fill out the form available [here](https://docs.google.com/forms/d/e/1FAIpQLSdH9sgfTz4v33lAvwj6BvYJGAeIshQia3FXz36PFfF-WQAWEQ/viewform) and wait for the Aligned team to approve your request.

### What Strategies Tokens are supported in Mainnet?

The list of supported strategies can be found [here](https://github.com/yetanotherco/aligned_layer/blob/testnet/docs/3_guides/7_contract_addresses.md).

### What RPC should I use?

We suggest you use your own nodes for better performance and reliability. Note that the node must support HTTP and WebSockets.

We also recommend the following RPC providers:

* [Infura](https://infura.io/)
* [Blast](https://blastapi.io/)

Two RPCs are used, one as the main one, and the other one as a fallback in case one node is working unreliably.

Default configurations is set up to use the same public node in both scenarios.

{% hint style="danger" %}
PUBLIC NODES SHOULDN'T BE USED AS THE MAIN RPC. We recommend not using public nodes at all.

FALLBACK AND MAIN RPCs SHOULD BE DIFFERENT.
{% endhint %}

Most of the actions will pass through the main RPC unless there is a problem with it. Events are fetched from both nodes.

### How can I check if the version I'm using is the latest one?

You can check the latest version available on the [releases' page](https://github.com/yetanotherco/aligned_layer/releases).

### How do I check the operator version registered on the Aligned version tracking system?

You can get the registered version of your operator by running the following command:

* Mainnet:

  ```bash
  curl https://mainnet.telemetry.alignedlayer.com/versions/<operator_address>
  ```
* Sepolia:

  ```bash
  curl https://sepolia.telemetry.alignedlayer.com/versions/<operator_address>
  ```
* Hoodi:

  ```bash
  curl https://hoodi.telemetry.alignedlayer.com/versions/<operator_address>
  ```

Replace `<operator_address>` with your operator address.

Also, you can check the operator version in the Explorer:

* [Mainnet Operators Explorer](https://explorer.alignedlayer.com/operators)
* [Sepolia Operators Explorer](https://sepolia.explorer.alignedlayer.com/operators)
* [Hoodi Operators Explorer](https://hoodi.explorer.alignedlayer.com/operators)

### How do I check the operator version locally?

To see the operator version, run:

```bash
./operator/build/aligned-operator --version
```

You have to be in the root `aligned-layer` directory to run this command.

This will show the version of the operator you have built in your filesystem.

### How do I get the ID of the operator?

You can get the ID of the operator by running the following command:

* Mainnet:

  ```bash
  cast call \
      --rpc-url https://ethereum-rpc.publicnode.com \
      0x3CcfB7e6e8fe2A8d941a8Ce4C69A944a770E8228 \
      "getOperatorId(address operator)(bytes32)" <operator_address>
  ```
* Sepolia:

  ```bash
  cast call \
      --rpc-url https://ethereum-sepolia-rpc.publicnode.com \
      0x0Ef1920F089DD02d3A28BF2e34342FD3e74160A3 \
      "getOperatorId(address operator)(bytes32)" <operator_address>
  ```
* Hoodi:

  ```bash
  cast call \
      --rpc-url https://ethereum-hoodi-rpc.publicnode.com \
      0xD06AAf23d136ECBfb5Bdb349Dd7a87aDc74673Dd \
      "getOperatorId(address operator)(bytes32)" <operator_address>
  ```

> Note: You need to have installed [Foundry](https://book.getfoundry.sh/)

This will return the operator ID if the operator is registered, otherwise it will return `0x`.


# Troubleshooting

### How to resolve the error "Error in new task subscription"

This error is caused by the operator not being able to subscribe to the task.

Make sure you have configured the RPC correctly and verify that the node is running.

The following RPC providers are known to have issues:

* [dRPC](https://drpc.org/)

### My operator is not showing up on the Aligned Explorer

The [explorer](https://explorer.alignedlayer.com/) does not update the operator status in real time. The explorer updates the operators' list every 1 hour.

If your operator is not showing up after 1 hour, please check the following:

* The operator is **whitelisted** on the Aligned AVS, you can run the following command:

  * Sepolia:

    ```bash
    cast call \
    --rpc-url https://ethereum-sepolia-rpc.publicnode.com \
    0x0Ef1920F089DD02d3A28BF2e34342FD3e74160A3 \
    "isWhitelisted(address _address)(bool)" <operator_address>
    ```
  * Hoodi:

    ```bash
    cast call \
    --rpc-url https://ethereum-hoodi-rpc.publicnode.com \
    0x87CD431F160e88EC34fA48EC6F6cF7F2C0E8248c \
    "isWhitelisted(address _address)(bool)" <operator_address>
    ```

  If the operator is whitelisted, it will return `true`.
* The operator is **registered** on the Aligned AVS:

  * Sepolia:

    ```bash
    cast call \
    --rpc-url https://ethereum-sepolia-rpc.publicnode.com \
    0x0Ef1920F089DD02d3A28BF2e34342FD3e74160A3 \
    "getOperatorId(address operator)(bytes32)" <operator_address>
    ```
  * Hoodi:

    ```bash
    cast call \
    --rpc-url https://ethereum-hoodi-rpc.publicnode.com \
    0xD06AAf23d136ECBfb5Bdb349Dd7a87aDc74673Dd \
    "getOperatorId(address operator)(bytes32)" <operator_address>
    ```

  If the operator is not registered, it will return `0x0` otherwise it will return the operator ID.

### How to resolve the error "Eth ws url or fallback is empty" or "Eth rpc url or fallback is empty"

This error is caused by the operator not being able to get the RPC urls.

Make sure you have configured the RPC correctly in the [config file](/operators/0_running_an_operator#step-3---update-the-configuration-for-your-specific-operator).

### How to update Rust

In case you have an unsupported version of Rust, you can update it following the [official page](https://www.rust-lang.org/tools/install)

### Compiler family detection failed due to error: ToolNotFound: failed to find tool "c++": No such file or directory (os error 2)

Run `sudo apt update && sudo apt install g++` to install the GNU C++ compiler.


# Upgrading Guides


# Upgrading to v0.14.0

This guide will walk you through the process of upgrading your Aligned Operator to v0.14.0.

Since EigenLayer released Slashing on Holesky Testnet, there are two versions of the [EigenSDK](https://github.com/Layr-Labs/eigensdk-go), one is compatible with Mainnet and the other one is compatible with Holesky Testnet. This guide will help you to upgrade your operator with the correct version of the EigenSDK.

The EigenSDK version [v0.1.13](https://github.com/Layr-Labs/eigensdk-go/releases/tag/v0.1.13) is compatible with Mainnet.

The EigenSDK version [v0.2.0-beta.1](https://github.com/Layr-Labs/eigensdk-go/releases/tag/v0.2.0-beta.1) is compatible with Holesky Testnet.

## Changes

This version includes the following changes:

* hotfix: eigensdk on Operator and Aggregator boot in [#1740](https://github.com/yetanotherco/aligned_layer/pull/1740)

## How to upgrade

Depending on the network you are running, you will need to upgrade the EigenSDK version on your operator.

For Mainnet this upgrade is optional, but for Holesky Testnet it is mandatory.

### Mainnet Operator

This upgrade is OPTIONAL for Mainnet operators. But, if you want to upgrade, you can follow the steps below:

#### Step 1 - Pull the latest changes

```shell
cd <path/to/aligned/repository>
git fetch origin
git checkout v0.14.0
```

#### Step 2 - Update the Operator

```shell
make build_operator ENVIRONMENT=mainnet
```

This will install the version v0.1.13 of the EigenSDK, and then it will recompile the binaries.

#### Step 3 - Check the Operator Version

To see the operator version, run:

```shell
./operator/build/aligned-operator --version
```

This will display the current version of the operator binary. The output should be:

```
Aligned Layer Node Operator version v0.14.0
```

#### Step 4 - Restart the Operator

Restart the operator based on your system configuration.

### Testnet Operator

This upgrade is MANDATORY for Testnet operators. Follow the steps below to upgrade your operator:

#### Step 1 - Pull the latest changes

```shell
cd <path/to/aligned/repository>
git fetch origin
git checkout v0.14.0
```

#### Step 2 - Update the Operator

```shell
make build_operator ENVIRONMENT=testnet
```

This will install the version v0.2.0-beta.1 of the EigenSDK, and then it will recompile the binaries.

#### Step 3 - Check the Operator Version

To see the operator version, run:

```shell
./operator/build/aligned-operator --version
```

This will display the current version of the operator binary. The output should be:

```
Aligned Layer Node Operator version v0.14.0
```

#### Step 4 - Restart the Operator

Restart the operator based on your system configuration.

### Troubleshooting

#### Operator not registered on Aligned

If your operator is not registered on Aligned, or it was ejected from the network, you can follow the registration process again.

* Mainnet:

```bash
make operator_register_with_aligned_layer CONFIG_FILE=./config-files/config-operator-mainnet.yaml
```

* Holesky:

```bash
make operator_register_with_aligned_layer CONFIG_FILE=./config-files/config-operator-holesky.yaml
```

{% hint style="danger" %}
If you are going to run the server in this machine, delete the operator key
{% endhint %}


# Upgrading to v0.10.2

This guide will walk you through the process of upgrading your Aligned Operator to v0.10.2.

## Changes

### New Features

* feat(telemetry): Add url data to operator updates on telemetry service in [#1136](https://github.com/yetanotherco/aligned_layer/pull/1136)
* fix: add panic catch on operator calling FFI in [#1196](https://github.com/yetanotherco/aligned_layer/pull/1196)
* refactor(operator): use url.Parse instead of regex for sending rpc information to telemetry service [#1327](https://github.com/yetanotherco/aligned_layer/pull/1327)
* feat(operator): bump risc0 and sp1 versions in [#1324](https://github.com/yetanotherco/aligned_layer/pull/1324)

## How to upgrade

### Step 1 - Update the configuration for your specific Operator

This version requires update the operator configuration file changing the following field:

```yaml
## Operator Configurations
operator:
  operator_tracker_ip_port_address: https://holesky.telemetry.alignedlayer.com
```

{% hint style="info" %}
Previous URL of operator\_tracker\_ip\_port\_address. Now it sends data to a telemetry server with better tracking and error handling
{% endhint %}

### Step 2 - Update the Operator

Inside the Aligned repository, run:

```bash
make update_operator
```

This will recompile the binaries. You can then proceed to restart the operator.

### Step 3 - Check the Operator Version

To see the operator version, run:

```bash
./operator/build/aligned-operator --version
```

This will display the current version of the operator binary.

```
Aligned Layer Node Operator version v0.10.2
```

### Step 4 - Restart the Operator

Restart the operator based on your system config


# Upgrading to v0.9.2

This guide will walk you through the process of upgrading your Aligned Operator to v0.9.2.

## Changes

### New Features

* fix: operator downtime by @MarcosNicolau in [#1073](https://github.com/yetanotherco/aligned_layer/pull/1073)
* fix: operator commands by @MarcosNicolau in [#1184](https://github.com/yetanotherco/aligned_layer/pull/1184)
* fix: operator resets channel when updating latest block file by @MarcosNicolau in [#1200](https://github.com/yetanotherco/aligned_layer/pull/1200)

## How to upgrade

### Step 1 - Update the configuration for your specific Operator

This version requires update the operator configuration file adding the following fields:

```yaml
## Operator Configurations
operator:
  last_processed_batch_filepath: '<path to a file to store the last processed batch>'
```

{% hint style="warning" %}
Make sure the directory where the file is stored exists and the operator has write permissions to it.

We suggest to use absolute paths to avoid ambiguity.
{% endhint %}

### Step 2 - Update the Operator

Inside the Aligned repository, run:

```bash
make update_operator
```

This will recreate the binaries. You can then proceed to restart the operator.

### Step 3 - Check the Operator Version

To see the operator version, run:

```bash
./operator/build/aligned-operator --version
```

This will display the current version of the operator binary.

```
Aligned Layer Node Operator version v0.9.2
```

### Step 4 - Restart the Operator

Restart the operator based on your system config


