# Avail Documentation > Avail is a modular blockchain focused on data availability and cross-chain interoperability. This documentation covers Avail DA (data availability layer) and Avail Nexus (cross-chain unification). ## Avail DA ### Get Started Welcome to the Avail documentation. Avail is a modular blockchain focused on data availability, enabling scalable and secure rollups and applications. ## Explore the Documentation - [**Avail DA**](/docs/da) — Learn about Avail's data availability layer - the foundation for scalable blockchain applications - [**Avail Nexus**](/docs/nexus) — Discover cross-chain interoperability and how to connect different blockchain ecosystems - [**User Guides**](/docs/da/user-guides) — Step-by-step guides for accounts, staking, bridging, and more ## Quick Links * **New to Avail?** Start with the [Introduction to Avail DA](/docs/da/get-started) * **Want to build?** Check out [Build](/docs/da/build) * **Running a node?** See [Operate](/docs/da/operate) * **Using Avail?** Browse the [User Guides](/docs/da/user-guides) ### Avail DA Welcome to the Avail DA documentation. Avail DA is the data availability layer that powers the Avail ecosystem. - [**Get Started**](/docs/da/get-started) — An overview of Avail DA and quick links to get up and running. - [**Concepts**](/docs/da/concepts) — Understand how Avail DA works — data availability, consensus, App IDs, and pricing. - [**Build**](/docs/da/build) — Integrate your rollup, post data, and connect to Avail DA. - [**Operate**](/docs/da/operate) — Run a light client, full node, or become a validator on the Avail network. - [**User Guides**](/docs/da/user-guides) — Accounts, staking, bridging, Ledger setup, and more. - [**API Reference**](/docs/da/api-reference) — Node API, light client API, bridge API, and Turbo DA API reference. ### API Reference > **Warning** > > 1. This section is dedicated towards providing a detailed API reference for all of Avail's APIs and SDKs. > 2. If you are working with older versions of Avail's SDKs, please refer to the menu next to the search bar to access the old API docs. This entire section is dedicated towards providing a detailed API reference for all of Avail's dev tooling. We currently document the following APIs: - [**Avail node API**](/docs/da/api-reference/avail-node-api) - [**Avail light client API**](/docs/da/api-reference/avail-lc-api) - [**Avail bridge API**](/docs/da/api-reference/avail-bridge-api) - [**Turbo DA API**](/docs/da/api-reference/avail-turbo-da-api) Questions? Errors? Something missing? Feel free to reach out to us on [our Discord server](https://discord.gg/AvailProject). ### Bug Bounty If you discover security vulnerabilities, **please report it responsibly** to help us keep the Avail ecosystem secure. ## Bug Bounty Program with Immunefi We offer rewards of upto $500,000 for valid security disclosures through our bug bounty program on Immunefi. 🔗 [View detailed information about the bug bounty on Immunefi](https://immunefi.com/bug-bounty/avail/information/) ### Contact us If your vulnerability is not in scope of the Immunefi program or you need to contact the team urgently, please email us at: 📨 **[security@availproject.org](mailto:security@availproject.org)** We appreciate your help in keeping Avail safe and reliable! ### Build Choose how to integrate with Avail DA. Start with [Interact](/docs/da/build/interact) to post and read data directly, or pick a rollup framework if you're deploying a chain. - [**Interact**](/docs/da/build/interact) — Post data, create App IDs, and query balances using the SDK or API. - [**Rollups**](/docs/da/build/rollups) — Deploy a rollup on Avail DA — OP Stack, Arbitrum Nitro, Polygon CDK, and more. - [**Turbo DA**](/docs/da/build/turbo-da) — High-throughput data submission optimized for production workloads. - [**Bridge**](/docs/da/build/vectorx) — Bridge tokens and data between Avail and other chains using VectorX. ### Concepts Key concepts you need to know before you start building with Avail DA. - [**What is Avail DA?**](/docs/da/concepts/what-is-avail-da) — A modular data availability layer purpose-built for rollups — scalable, verifiable DA without execution overhead. - [**How Avail DA Works**](/docs/da/concepts/how-avail-da-works) — Erasure coding, KZG commitments, data availability sampling, and how blocks are finalized. - [**What are App IDs?**](/docs/da/concepts/app-ids) — Unique identifiers that separate and filter data submissions on Avail DA by application. - [**Using the Explorer**](/docs/da/concepts/explorer) — Browse blocks, transactions, and validators on Avail DA using the network explorers. - [**How Transaction Pricing Works**](/docs/da/concepts/tx-pricing) — How AVAIL token fees are calculated based on compute and storage requirements. ### FAQs ## What problem does Avail solve? Avail is solving fundamental scaling and user experience problems. Cross-ecosystem transactions are cumbersome and difficult, driving more fragmentation throughout an already fragmented ecosystem and this makes it hard for app developers to onboard new users and liquidity. Avail addresses these issues from first principles, solving scalability with the first DA layer to anchor modular blockchains using cutting-edge zero knowledge technology to ensure responsive and reliable data availability. Avail Nexus is a general purpose interoperability protocol, that will leverage Avail DA as the root of trust. App developers can use Avail Nexus to quickly onboard users and liquidity into their new apps. Blockchain developers can use Avail DA to build hyper-scalable and cost efficient blockchain solutions. ## How can I get involved? * [Use Avail DA](https://docs.availproject.org/) for your chain * Run a [Validator](https://docs.availproject.org/da/operate-a-node/become-a-validator) * Run a [light client](https://docs.availproject.org/da/operate-a-node/run-a-light-client) * Join [Discord](https://discord.gg/AvailProject) * Follow us on [X](https://x.com/AvailProject) * Join the [Avail Uncharted](https://github.com/availproject/avail-uncharted) Technical Contributor's program ## How do I get in touch if I have questions? * Business → [business@availproject.org](mailto:business@availproject.org) * Technical questions → [Discord](https://discord.gg/AvailProject) or [Forum](https://forum.availproject.org/) ## I found a bug/vulnerability. Where do I report it? We have a bug bounty program where you can report the vulnerability. Please check out the [Bug Bounty](/docs/da/bug-bounty) page for detailed information on how to responsibly report it. ## What is a popular use case of a light client? There are many use-cases which today rely on an intermediary to maintain a full node, such that end users of a blockchain do not communicate directly with the blockchain but instead through the intermediary. Light clients have until now not been a suitable replacement for this architecture because they lacked data availability guarantees. Avail solves this issue, thus enabling more applications to directly participate on the blockchain network without intermediaries. Although Avail does support full nodes, we expect most applications will not need to run one, or will need to run fewer. ## What is data availability sampling (DAS)? Avail DA light clients, like other light clients, only download the headers of the blockchain. However, they additionally perform data availability sampling: a technique that randomly samples small sections of the block data and verifies they are correct. When combined with erasure coding and KZG polynomial commitments, light clients are able to provide strong (nearly 100%) guarantees of availability without relying on fraud proofs, and with only a small constant number of queries. ## How is erasure coding used to increase data availability guarantees? Erasure coding is a technique that encodes data in a way that spreads out the information over multiple 'shards', such that the loss of some number of those shards can be tolerated. That is, the information can be reconstructed from the other shards. Applied to the blockchain, this means that we effectively increase the size of each block, but we prevent a malicious actor from being able to hide any part of a block up to the redundant shard size. Since a malicious actor needs to hide a large part of the block in order to attempt to hide even a single transaction, it makes it much more likely that random sampling would catch the large gaps in the data. Effectively, erasure coding makes the data availability sampling technique much more powerful. ## What are KZG commitments? KZG commitments, introduced by Aniket Kate, Gregory M. Zaverucha, and Ian Goldberg in 2010, provide a way to commit to polynomials in a succinct manner. Recently, polynomial commitments came to the forefront, being primarily used as commitments in PLONK-like zero knowledge constructions. In our construction, we use KZG commitments for the following reasons: * It allows us to commit to values in a succinct manner to be kept inside the block header. * Short openings are possible which helps a light client verify availability. * The cryptographic binding property helps us avoid fraud proofs by making it computationally infeasible to produce incorrect commitments. In the future, we might use other polynomial commitment schemes, if that gives us better bounds or guarantees. ## Since Avail is used by multiple applications, does that mean chains have to download transactions from other chains? No. Avail headers contain an index that allows a given application to determine and download only the sections of a block that have data for that application. Thus, they are largely unaffected by other chains using Avail at the same time or by block sizes. The only exception is data availability sampling. In order to verify that data is available (and due to the nature of erasure coding), clients sample small parts of the block at random, including possibly sections that contain data for other applications. ## Who is behind Avail? Avail is led by former Polygon co-founder [Anurag Arjun](https://x.com/anuragarjun) and former Polygon research lead [Prabal Banerjee](https://x.com/prabalbanerjee). The [Avail team](https://availproject.org/aboutus) consists of more than 40 professionals with solid experience in their areas of expertise ranging from marketing to blockchain design and programming. Many have proven track records in the Web3 space and a diverse background that forms the foundation of a solid team. ### Get Started with Avail DA Avail DA is a modular data availability layer purpose-built so rollups can post, verify, and retrieve data without running a full node. Rollup teams across the ecosystem use Avail DA to scale throughput while keeping verification light and decentralized. On this page you'll install an SDK, submit data to the Turing testnet, and read it back — in under 5 minutes. ## Quick Look — Submit & Read Data #### TypeScript ```typescript import { Account, SDK, Block } from "avail-js-sdk"; const sdk = await SDK.New("wss://turing-rpc.avail.so/ws"); const account = Account.new("YOUR_SEED_PHRASE"); // Step 1: Submit data const tx = sdk.tx.dataAvailability.submitData("Hello, Avail!"); const res = await tx.executeWaitForInclusion(account, { app_id: 89 }); console.log(`Block: ${res.blockHash} | Tx: ${res.txHash}`); // Step 2: Read it back const block = await Block.New(sdk.client, res.blockHash); const blobs = block.dataSubmissions({ txHash: res.txHash }); console.log(blobs[0].toAscii()); // "Hello, Avail!" ``` #### Rust ```rust use avail_rust::prelude::*; let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let account = account::from_secret_uri("YOUR_SEED_PHRASE")?; // Step 1: Submit data let data = String::from("Hello, Avail!").into_bytes(); let tx = sdk.tx.data_availability.submit_data(data); let options = Options::new().app_id(89); let res = tx.execute_and_watch_inclusion(&account, options).await?; println!("Block: {:?} | Tx: {:?}", res.block_hash, res.tx_hash); // Step 2: Read it back let block = Block::new(&sdk.client, res.block_hash).await?; let blobs = block.data_submissions(Filter::new().tx_hash(res.tx_hash)); println!("{:?}", blobs[0].to_ascii().unwrap()); // "Hello, Avail!" ``` #### Go ```go sdk, _ := SDK.NewSDK("https://turing-rpc.avail.so/rpc") acc, _ := SDK.Account.NewKeyPair("YOUR_SEED_PHRASE") // Step 1: Submit data tx := sdk.Tx.DataAvailability.SubmitData([]byte("Hello, Avail!")) res, _ := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions().WithAppId(89)) fmt.Println("Block:", res.BlockHash.ToHexWith0x(), "| Tx:", res.TxHash.ToHexWith0x()) // Step 2: Read it back block, _ := SDK.NewBlock(sdk.Client, res.BlockHash) blobs := block.DataSubmissions(SDK.Filter{}.WTxHash(res.TxHash)) fmt.Println(string(blobs[0].Data)) // "Hello, Avail!" ``` For complete examples with error handling, see the [full Read & Write guide](/docs/da/build/interact/read-write-on-avail). > **Note** > > **Prerequisites:** Before running the code above, you'll need: > > * [Testnet AVAIL tokens](/docs/da/build/interact/faucet) — free from the faucet > * [An App ID](/docs/da/build/interact/app-id) — identifies your data namespace > * An SDK installed: `pnpm add avail-js-sdk` · `cargo add avail-rust` · `go get github.com/availproject/avail-go-sdk` ## Choose Your Path - [**Post Data to Avail**](/docs/da/build/interact/read-write-on-avail) — Full read & write tutorial with TypeScript, Rust, and Go SDKs. ~15 min. - [**Deploy a Rollup**](/docs/da/build/rollups) — Launch an OP Stack, Arbitrum Nitro, or Polygon CDK rollup on Avail DA. - [**Run a Light Client**](/docs/da/operate/run-a-light-client) — Verify data availability by sampling — no full node needed. ~10 min. - [**Run a Validator**](/docs/da/operate/become-a-validator) — Operate a full validator node on the Avail network. ## Next Steps - [**Explore Concepts**](/docs/da/concepts) — What is Avail DA, how it works, App IDs, and transaction pricing. - [**API Reference**](/docs/da/api-reference) — Node API, Light Client API, Bridge API, and Turbo DA API. - [**Networks & Endpoints**](/docs/da/networks) — Mainnet and Turing testnet RPC/WS endpoints and explorers. ### Glossary ## App-Chain An appchain is an independent blockchain tailored to a specific application's needs, providing dedicated performance and scalability without the constraints of a shared chain. Avail enables modular appchain architectures based on different layer 2 or 3 scaling solutions. ## AVAIL AVAIL is the native token of the Avail network. The AVAIL token is live on Mainnet; [learn more about the AVAIL token here](/docs/da/user-guides/staking-governance/overview). ## Avail JS Apps The Avail JS Apps UI is a forked version of [Polkadot JS Apps UI](https://polkadot.js.org/apps/) used for visualizing and interacting with the Avail network. ## BABE BABE (Blind Assignment for Blockchain Extension), part of the Substrate framework, is the block production mechanism that Avail uses. Refer to the [Polkadot Wiki](https://wiki.polkadot.network/docs/learn-consensus#block-production-babe) for more details. ## Bonding Bonding is the process of locking tokens to participate in network operations such as consensus and security. ## Chilling Chilling is the act of withdrawing from nominating or validating roles, effective in the subsequent era. It can also refer to a validator being excluded from the active set by peers, making them ineligible for the next consensus cycle. ## Commission Validators set a commission rate that is deducted from their block production rewards. The remaining rewards are distributed to nominators backing that validator. ## Consensus Consensus is the mechanism by which nodes agree on what blockchain data is valid. Avail uses [NPoS](#nominated-proof-of-stake) as its consensus protocol. ## Controller Account The controller account manages staking activities — nominating validators, bonding/unbonding funds, and paying transaction fees. It is used more frequently than the stash account for day-to-day operations. ## Data Attestation Data attestation confirms the authenticity and accessibility of on-chain data. Avail block headers include KZG polynomial commitments for data and a Merkle tree root with data blobs as leaves. A supermajority of validators finalize headers using the [GRANDPA](#grandpa) protocol. ## Data Availability Committee (DAC) A DAC is a group of nodes that preserves copies of off-chain data and ensures its accessibility on demand. Unlike DACs, which typically serve specific L2 solutions, Avail is a general-purpose data availability layer that operates as an autonomous chain. ## Data Availability Sampling (DAS) DAS allows light clients to confirm data availability without downloading full blocks. Light clients randomly sample small chunks of block data across multiple rounds, with confidence growing after each successful round until a set threshold is reached. ## DHT (Distributed Hash Table) A DHT is a decentralized lookup system that holds key-value pairs, enabling peers to quickly find data. In Avail, the DHT facilitates sharing data cells for random sampling and proof verification, connecting nodes for efficient cell discovery and access. ## Decoupling Decoupling in blockchain refers to separating distinct functionalities into independent modules or layers. This modular approach allows each component to specialize, evolve, and scale independently. ## Equivocation Equivocation is when a validator signs two or more conflicting blocks or messages. This can be done intentionally or unintentionally. ## Era An era in Avail is a predefined number of [sessions](#session) during which the validator set is determined and rewards are distributed. At each era boundary, validators are selected for the active set based on stake amount and prior performance. ## Epoch An epoch is a designated time frame during which a specific group of validators verifies transactions and appends them to the blockchain. Epoch duration varies across networks. ## Execution In traditional blockchains, execution is how nodes process transactions to transition state. Avail does not have a general-purpose execution layer — execution occurs in other layers (such as rollups), and the resulting data is posted to Avail in raw form. Avail validators do not execute transactions to attest to block validity. They primarily attest to the correct packaging of published data, which is why Avail can accommodate larger block sizes with reduced per-block overhead. ## Finality Gadget A finality gadget ensures blockchain state finality by requiring validators to commit through signed messages. Once sufficiently validated, the state is finalized and secure from modification. ## Fraud Proofs Fraud proofs are cryptographic proofs used to challenge the legitimacy of a transaction or state transition. Any node can generate and share a fraud proof across the P2P network for app clients to assess. ## GRANDPA GRANDPA (GHOST-based Recursive Ancestor Deriving Prefix Agreement), part of the Substrate framework, is the finality gadget Avail uses. Refer to [the GRANDPA paper](https://github.com/w3f/consensus/blob/master/pdf/grandpa.pdf) for the full protocol description. ## KZG Commitments KZG commitments, introduced by Kate, Zaverucha, and Goldberg in 2010, are a concise method for committing to polynomials. Avail uses KZG commitments because they enable succinct commitments for block headers, support brief openings for light client verification, and provide strong cryptographic binding that prevents fraudulent commitments. ## Kademlia DHT (Kad-DHT) Kad-DHT is a DHT variant that organizes nodes on a chord ring ordered by ID. Avail uses Kad-DHT to store data cells and locate which peer holds a particular data segment, with matrix data cells uniquely mapped to Peer IDs. ## libp2p [libp2p](https://libp2p.io/) is an open-source modular network stack for building P2P applications. Avail integrates libp2p to establish a decentralized network for data availability, ensuring transaction data is efficiently stored and disseminated to validators and full nodes. ## Light Client Light clients allow users to interact with a blockchain without syncing the full chain, typically retrieving only block headers. Avail light clients enhance this with Data Availability Sampling, downloading and verifying random block segments to confirm content availability. ## Mainnet A mainnet is the fully operational, public "production" version of a blockchain network where real transactions and applications run. See the ["Mainnet is Live!" blog post](https://blog.availproject.org/road-to-mainnet-september-2023/) for details on Avail's mainnet. ## Modular Blockchain A modular blockchain specializes in specific tasks while delegating other responsibilities to distinct layers or components. ## Monolithic Blockchain A monolithic blockchain handles all core functionalities (execution, settlement, ordering, data availability) within a single structure. ## Nominated Proof of Stake Nominated Proof of Stake (NPoS) is a consensus algorithm where users nominate validators to produce blocks on their behalf. Validators receive rewards in native tokens and share a portion with nominators based on a set commission rate. Avail uses NPoS as implemented within Substrate. ## Oversubscribed Oversubscribed refers to when the number of nominators wishing to participate exceeds the available slots. ## Scalability Scalability in Avail refers to increasing the volume of data the chain can disseminate without degrading participant experience. Avail achieves this through a modular approach that moves DA off-chain, allowing each component to scale independently. ## Session A session is a specific duration during which a fixed set of validators operate. Validators can enter or exit the set only at session boundaries. ## Settlement Settlement is the process by which modular layers agree on the correct execution outcome of transaction data. Avail receives and stores raw transaction data without executing it — actual execution and validation occur in other layers, with results settled through mechanisms like validity proofs on Ethereum. ## Slashing Slashing is a penalty imposed on validators who misbehave (e.g., equivocation). It can result in the loss of a portion of the validator's stake. ## Sovereign Rollup A sovereign rollup publishes transactions to another blockchain for ordering and data availability but handles its own settlement. It maintains its own canonical chain and validity rules without relying on an external settlement layer. ## Stash Account The stash account holds the tokens you wish to stake/bond. It functions as cold storage and is used for bonding, unbonding, and designating the controller account. ## Testnet A testnet is a simulated blockchain network used to test and debug applications before mainnet deployment. Testnets are typically open to public participation. ## Validium A validium stores transaction data off the primary L1 (e.g., Ethereum) and can leverage Avail's scalable DA module. Rather than directing data to a [DAC](#data-availability-committee-dac) or other alternatives, validiums can commit data to Avail. Essentially, a validium is a rollup with off-chain data availability. ## Validator An Avail validator is a full node responsible for verifying transactions and adding them to the blockchain. ## Volition A volition is an advanced form of zero-knowledge rollup that lets developers choose whether to store transaction data on-chain or off-chain. Volitions can leverage Avail's DA layer to keep off-chain data accessible and verifiable, optimizing for both cost and availability. ### Network Information > **Note** > > As of now, **Turing** is the only supported testnet on Avail. **Kate** & **Goldberg** have been decommissioned. > We will keep this page updated with the latest information on new networks. **The Turing Testnet is the latest test network of the Avail Project.** | | **Mainnet** | **Turing Testnet** | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Status** | **Active** | **Active** | | **Subscan Explorer** | [avail.subscan.io](https://avail.subscan.io/) | [avail-turing.subscan.io](https://avail-turing.subscan.io/) | | **AvailApps Explorer** | [mainnet.explorer.availproject.org](https://explorer.availproject.org/?rpc=wss%3A%2F%2Fmainnet-rpc.avail.so%2Fws\&light=https%3A%2F%2Fapi.lightclient.mainnet.avail.so%2Fv1) | [turing.explorer.availproject.org](https://explorer.availproject.org/?rpc=wss%3A%2F%2Fturing-rpc.avail.so%2Fws\&light=https%3A%2F%2Fapi.lightclient.turing.avail.so%2Fv1) | | **Chain Spec** | [chainspec.raw.json](https://raw.githubusercontent.com/availproject/avail/main/misc/genesis/mainnet.chain.spec.raw.json) | [chainspec.raw.json](https://github.com/availproject/avail/blob/main/misc/genesis/testnet.turing.chain.spec.raw.json) | | **Node Version** | [Latest release](https://github.com/availproject/avail/releases) | [Latest release](https://github.com/availproject/avail/releases) | | **Light Client Version** | [Latest release](https://github.com/availproject/avail-light/releases) | [Latest release](https://github.com/availproject/avail-light/releases) | ## Avail DA - Ethereum Bridge ### For end users You can use the official [Avail bridge UI](https://bridge.availproject.org/) to bridge AVAIL between the two networks. You can find detailed instructions [in our docs here](/docs/da/user-guides/bridge-avail/avail-ethereum). ### For devs The following tables contains a list of endpoints and contract addresses for all relevant deployments of the VectorX bridge. #### VectorX Bridge | **Category** | **Mainnet** | **Testnet** | | -------------------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | **Bridge API** | [https://bridge-api.avail.so/](https://bridge-api.avail.so/) | [https://turing-bridge-api.avail.so/](https://turing-bridge-api.avail.so/) | | **VectorX Contract** | [0x02993cdC11213985b9B13224f3aF289F03bf298d](https://etherscan.io/address/0x02993cdC11213985b9B13224f3aF289F03bf298d) | [0xe542db219a7e2b29c7aeaeace242c9a2cd528f96](https://sepolia.etherscan.io/address/0xe542db219a7e2b29c7aeaeace242c9a2cd528f96) | | **Bridge Contract** | [0x054fd961708d8e2b9c10a63f6157c74458889f0a](https://etherscan.io/address/0x054fd961708d8e2b9c10a63f6157c74458889f0a) | [0x967F7DdC4ec508462231849AE81eeaa68Ad01389](https://sepolia.etherscan.io/address/0x967F7DdC4ec508462231849AE81eeaa68Ad01389) | #### AVAIL Token #### Ethereum | **Network** | **Token Address** | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | **Ethereum Mainnet** | [0xEeB4d8400AEefafC1B2953e0094134A887C76Bd8](https://etherscan.io/token/0xEeB4d8400AEefafC1B2953e0094134A887C76Bd8) | | **Sepolia Testnet** | [0xb1c3cb9b5e598d4e95a85870e7812b99f350982d](https://sepolia.etherscan.io/address/0xb1c3cb9b5e598d4e95a85870e7812b99f350982d) | #### Base | **Network** | **Token Address** | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | | **Base Mainnet** | [0xd89d90d26b48940fa8f58385fe84625d468e057a](https://basescan.org/address/0xd89d90d26b48940fa8f58385fe84625d468e057a) | | **Base-Sepolia Testnet** | [0xf50F2B4D58ce2A24b62e480d795A974eD0f77A58](https://sepolia.basescan.org/address/0xf50F2B4D58ce2A24b62e480d795A974eD0f77A58) | #### Other deployments ##### Timelock | **Network** | **Timelock Contract Address** | | -------------------- | --------------------------------------------------------------------------------------------------------------------- | | **Ethereum Mainnet** | [0x45828180bbE489350D621d002968A0585406d487](https://etherscan.io/address/0x45828180bbE489350D621d002968A0585406d487) | ##### Governance | **Network** | **Governance Contract Address** | | -------------------- | --------------------------------------------------------------------------------------------------------------------- | | **Ethereum Mainnet** | [0x7f2f87b0efc66fea0b7c30c61654e53c37993666](https://etherscan.io/address/0x7f2f87b0efc66fea0b7c30c61654e53c37993666) | {/* | **Bridge Indexer** | [zeref-bridge-indexer.fra.avail.so](https://zeref-bridge-indexer.fra.avail.so) | [turing-bridge-indexer.fra.avail.so](https://turing-bridge-indexer.fra.avail.so/) | */} {/* | **Operator** | Deployed | Deployed | */} ## Alternate Endpoints We at Avail have teamed up with some external partners to provide alternate endpoints for people to connect to Avail DA. We will keep this table updated as we onboard more partners. ### Mainnet | **Partner** | **RPC Endpoint (Mainnet)** | **WSS Endpoint (Mainnet)** | | --------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | **OnFinality** | [https://avail.api.onfinality.io/public](https://avail.api.onfinality.io/public) | [wss://avail.api.onfinality.io/public-ws](wss://avail.api.onfinality.io/public-ws) | | **Ankr** | [https://mainnet.avail-rpc.com/](https://mainnet.avail-rpc.com/) | [wss://mainnet.avail-rpc.com/](wss://mainnet.avail-rpc.com/) | | **All Nodes** | [https://avail-rpc.publicnode.com/](https://avail-rpc.publicnode.com/) | [wss://avail-rpc.publicnode.com/](wss://avail-rpc.publicnode.com/) | | **VitWit** | [https://avail.rpc.vitwit.com/](https://avail.rpc.vitwit.com/) | [wss://avail.rpc.vitwit.com/](wss://avail.rpc.vitwit.com/) | | **GlobalStake** | [https://rpc-avail.globalstake.io](https://rpc-avail.globalstake.io) | [wss://rpc-avail.globalstake.io](wss://rpc-avail.globalstake.io) | | **RadiumBlock** | [https://avail.public.curie.radiumblock.co/http](https://avail.public.curie.radiumblock.co/http) | [wss://avail.public.curie.radiumblock.co/ws](wss://avail.public.curie.radiumblock.co/ws) | | **StakePool** | [https://rpc.avail.stakepool.dev.br/rpc](https://rpc.avail.stakepool.dev.br/rpc) | [wss://rpc.avail.stakepool.dev.br/ws](wss://rpc.avail.stakepool.dev.br/ws) | ### Turing Testnet | **Partner** | **RPC Endpoint (Turing)** | **WSS Endpoint (Turing)** | | --------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | **OnFinality** | [https://avail-turing.api.onfinality.io/public](https://avail-turing.api.onfinality.io/public) | [wss://avail-turing.api.onfinality.io/public-ws](wss://avail-turing.api.onfinality.io/public-ws) | | **Ankr** | [https://rpc.ankr.com/avail\_turing\_testnet](https://rpc.ankr.com/avail_turing_testnet) | [wss://turing-testnet.avail-rpc.com](wss://turing-testnet.avail-rpc.com) | | **AllNodes** | [https://avail-turing-rpc.publicnode.com](https://avail-turing-rpc.publicnode.com) | [wss://avail-turing-rpc.publicnode.com](wss://avail-turing-rpc.publicnode.com) | | **RadiumBlock** | [https://turing.public.curie.radiumblock.co/http](https://turing.public.curie.radiumblock.co/http) | [wss://turing.public.curie.radiumblock.co/ws](wss://turing.public.curie.radiumblock.co/ws) | ### Operate Run Avail DA infrastructure. Start with [Node Types](/docs/da/operate/node-types) to understand the options, or jump straight to the setup guide for your target role. - [**Node Types**](/docs/da/operate/node-types) — Compare light clients, full nodes, and validators — requirements, trade-offs, and use cases. - [**Hosted Deployments**](/docs/da/operate/deployment-options) — Deploy Avail nodes using third-party infrastructure providers. - [**Light Client**](/docs/da/operate/run-a-light-client) — Verify data availability through sampling without storing full blocks. - [**Full Node**](/docs/da/operate/run-a-full-node) — Store complete block data and serve the network. - [**Validator**](/docs/da/operate/become-a-validator) — Produce blocks, validate transactions, and earn staking rewards. ### User Guides Step-by-step guides for interacting with the Avail network as an end user. ## Getting Started - [**Accounts**](/docs/da/user-guides/accounts) — Create and manage your Avail wallet accounts. - [**Using the Explorer**](/docs/da/user-guides/explorer) — Browse blocks, transactions, and validators using the network explorers. - [**Identity**](/docs/da/user-guides/identity) — Set an on-chain identity on the Avail network. ## Staking & Governance - [**Staking & Governance**](/docs/da/user-guides/staking-governance) — Stake AVAIL tokens, nominate validators, and participate in on-chain governance. - [**Bridge AVAIL**](/docs/da/user-guides/bridge-avail) — Bridge AVAIL tokens between Avail and other chains. ## Security & Advanced - [**Ledger**](/docs/da/user-guides/ledger-avail) — Use a Ledger hardware wallet to manage your AVAIL tokens securely. - [**Fund Recovery**](/docs/da/user-guides/avail-funds-recovery) — Recover funds from a Polkadot-derived Ledger address on the Avail network. - [**MetaMask Snap**](/docs/da/user-guides/avail-snap) — Interact with Avail DA directly from MetaMask using the Avail Snap. - [**Multisig**](/docs/da/user-guides/avail-multisig) — Create and manage multisig accounts for shared control of funds. - [**Proxies**](/docs/da/user-guides/proxies-on-avail) — Set up proxy accounts to delegate specific actions without exposing your main keys. ### Bridge API > **Warning** > > **TRANSACTION NESTING LIMITATIONS** > > To ensure network stability and security, the Avail network is generally subject to the following limits: > > 1. **General Transactions**: Transaction nesting is limited to a maximum of 5 levels. Transactions exceeding this limit are not guaranteed to be processed successfully. > > 2. **Bridge Transactions (Avail to Ethereum)**: For `vector.sendMessage` operations, only direct calls and nesting only with proxy/multisig (up to 2 levels) are supported. Any other combination is not guaranteed to work. > > 3. **Data Availability Submissions**: `dataAvailability.submitData` operations should only be performed with standard accounts. > > 4. **Batching Restrictions**: > * `vector.sendMessage` and `dataAvailability.submitData` calls should not be included in batch calls. > * `vector.sendMessage` should not be included in schedule calls. > * Transactions with more than 2 levels of batching are not guaranteed to work. > > **Understanding Nesting Levels**: > > * Level 0: Direct call (e.g., `dataAvailability.submitData`) > * Level 1: One wrapper (e.g., multisig → `dataAvailability.submitData`) > * Level 2: Two wrappers (e.g., proxy → multisig → `dataAvailability.submitData`) > **Note** > > **BEFORE WE START** > > 1. The Avail VectorX bridge can be used to pass messages and tokens between \ > Avail DA Turing - Ethereum Sepolia (testnet bridge), > and between Avail DA mainnet - Ethereum mainnet (mainnet bridge). > 2. You can check out a complete list of endpoints required to use the bridge API in the [networks page](/docs/da/networks#for-devs). > **Note** > > **TWO WAYS OF USING THE BRIDGE API** > > 1. You can build and run the bridge API locally using the instructions outlined in this repo: > [availproject/bridge-api](https://github.com/availproject/bridge-api) > 2. We have included two public endpoints for the bridge API in the [networks page](/docs/da/networks#for-devs) that you can use. > For the sake of simplicity that is what we will be using in this guide. > 3. For the sake of simplicity, we will use the Turing testnet bridge API in this guide. ## Setting up the dev environment #### CURL 1. To use the Avail bridge API with `curl`, you just need to have `curl` installed on your system. You can check if it is installed by running: ```bash filename="CURL" curl --version ``` 2. If this does not work, go to [curl's website](https://curl.se/) to install it on your system. #### avail-rust 1. Make sure `rust` and cargo are installed on your system. You can refer to [Rustlang's docs](https://www.rust-lang.org/tools/install) for the same. 2. Create a new Rust project by running `cargo init`. 3. Paste the following into your `Cargo.toml` file: ```toml [package] name = "avail_bridge_tools" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] avail-rust = { git = "https://github.com/availproject/avail" } tokio = { version = "1.35", features = ["full"] } codec = { package = "parity-scale-codec", version = "3", default-features = false, features = [ "derive", "full", "bit-vec", ] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.127" sp-core = { version = "21.0.0" } hex = "0.4" hex-literal = "0.3.4" anyhow = "1.0.79" reqwest = { version = "0.11.24", features = ["json"] } ringbuffer = { version = "0.15.0", features = ["alloc"] } secp256k1 = "0.28" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["json", "env-filter"] } chrono = "0.4.34" confy = "0.6" tokio-test = "0.4" alloy-sol-types = { version = "0.7.4", features = ["json"] } alloy-sol-macro = { version = "0.7.4", features = ["json"] } alloy = { git = "https://github.com/alloy-rs/alloy", version = "0.2.1" } alloy-contract = { git = "https://github.com/alloy-rs/alloy", version = "0.2.1" } alloy-provider = { git = "https://github.com/alloy-rs/alloy", version = "0.2.1" } alloy-network = { git = "https://github.com/alloy-rs/alloy", version = "0.2.1" } # alloy-primitives = { git = "https://github.com/alloy-rs/alloy", version = "0.2.1" } alloy-signer = { git = "https://github.com/alloy-rs/alloy", version = "0.2.1" } alloy-signer-local = { git = "https://github.com/alloy-rs/alloy", version = "0.2.1" } toml = "0.8.19" [profile.release] panic = 'abort' ``` 4. Create a `config.toml` file in the root of your project and paste the following: ```toml avail_rpc_url="wss://turing-rpc.avail.so/ws" avail_mnemonic = "A seed phrase for an Avail DA wallet" ethereum_mnemonic = "A seed phrase for an Ethereum wallet" # testnet bridge API bridge_api_url="https://turing-bridge-api.avail.so/" # Ethereum sepolia public node URL ethereum_url="https://ethereum-sepolia.publicnode.com" # Sepolia bridge contract address contract_address= "967F7DdC4ec508462231849AE81eeaa68Ad01389" message_data= "Random data to send" amount_to_send= 1000000 # Enter a Sepolia recipient address recipient="AfF84d35f9c784cE972A7Ff3e3E243E5eb6EF37D000000000000000000000000" receive_message_contract_address="29190B4d80C409A3DaF743F57379e0453D31C26b" ``` ### Light Client API > **Note** > > **BEFORE WE START** > > 1. The Avail light client(Avail LC) can run in two modes: `Light-client` or `App-client`. We internally maintain > a light client instance available for public use running in the `Light-client` mode. Thus, for all methods that can > be called via an LC running in the `Light-client` mode, devs can use our public endpoint. > 2. For methods that require an LC running in the `App-client` mode, you will need to run a local instance of the Avail LC. > 3. You can check out or docs for [instructions on running your own instance > of the Avail light client](/docs/da/operate/run-a-light-client/light-client) > 4. The LC API is exposed by default through `localhost:7007` by default. ## Setting up the dev environment Set up your dev environment with `curl` and `Rust`: #### CURL 1. To use the Avail light client API with `curl`, you just need to have `curl` installed on your system. You can check if it is installed by running: ```bash filename="CURL" curl --version ``` 2. If this does not work, go to [curl's website](https://curl.se/) to install it on your system. #### Rust How to run the Rust code snippets: 1. Make sure you have [Rust](https://www.rust-lang.org) and [Cargo](https://crates.io/) installed on your system before moving forward. You can check that by running: ```sh rustc --version && cargo --version ``` If either of these don't work, you can check out [Rust's official installation guide](https://www.rust-lang.org/tools/install). 2. Create a new Rust project: ```sh cargo new ``` 3. Add these dependencies to the `Cargo.toml` file: ```toml [dependencies] reqwest = { version = "0.12", features = ["json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tokio = { version = "1.36", features = ["full"] } base64 = "0.22" ``` 4. Paste the code snippets into the `main.rs` file, and run the project with `cargo run`. ### Turbo DA API > **Note** > > **NEED AN API KEY? OR ANY OTHER HELP TO GET STARTED?** > Please go through [this page in our docs](/docs/da/build/turbo-da) to get started with Turbo DA > before you get started with the API. ## Turbo DA endpoints | | **Mainnet** | **Turing Testnet** | | ----------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------- | | **Frontend** | [turbo.availproject.org](https://turbo.availproject.org/) | [staging.turbo.availproject.org](https://staging.turbo.availproject.org/) | | **API Endpoints** | [turbo-api.availproject.org](https://turbo-api.availproject.org/) | [staging.turbo-api.availproject.org](https://staging.turbo-api.availproject.org/) | ## Setting up the dev environment 1. To use the Turbo DA API as documented in the following pages, you just need to have `curl` installed on your system. You can check if it is installed by running: ```bash filename="CURL" curl --version ``` 2. If this does not work, go to [curl's website](https://curl.se/) to install it on your system. ### Node API > **Note** > > **BEFORE WE START** > > 1. The Avail node supports an extensive list of extrinsics and various other types of calls that you can > [try out in our explorer](https://explorer.availproject.org/#/extrinsics). > 2. This API reference currently documents only the most widely used extrinsics, but will be iterated upon > to eventually be an exhaustive resource for the Avail node API. ## Setting up the dev environment #### avail-js 1. Make sure `Node-js` is installed on your system by running the following command in your terminal: ```bash filename="terminal" name="cmd1" node --version ``` If not installed, you can refer to [Node-js docs](https://nodejs.org/en/download/package-manager) for the same. 2. Create a new Node-js project by running the following command in a directory of your choice: ```bash filename="terminal" name="cmd2" pnpm init ``` 3. To install the `avail-js-sdk` run the following command: ```bash filename="terminal" name="cmd3" pnpm add avail-js-sdk@0.4.1 ``` 4. Make sure to install the `ts-node` package if you haven't already: ```bash filename="terminal" name="cmd4" pnpm add -g ts-node ``` 5. Create a `tsconfig.json` file in the root of your project by running: ```bash filename="terminal" name="cmd5" touch tsconfig.json ``` 6. Populate your `tsconfig.json` with the following configuration: ```json showLineNumbers filename="tsconfig.json" name="cmd6" { "compilerOptions": { "target": "es2016", "module": "commonjs", "outDir": "build", "declaration": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "noUnusedParameters": true }, "include": ["**/*.ts", "**/*.js"], "exclude": ["node_modules", "build"] } ``` 7. Create a `.env` file in the root of your project by running: ```bash filename="terminal" name="cmd7" pnpm add dotenv && touch .env ``` 8. Put in the Seed Phrase of the account you want to use into the `.env` file: ```bash showLineNumbers filename=".env" name="cmd8" SEED="This is a random seed phrase please replace with your own" ``` > **Error** > > **IMPORTANT** > > 1. Please be **VERY CAREFUL** with your seed phrase. > 2. Make sure to add your `.env` file to your `.gitignore` so that it doesn't get pushed anywhere. > 3. While it is good enough to use an `env` file while testing, try to use better practices while deploying to production. #### avail-deno > **Warning** > > **AVAIL-DENO HAS BEEN SUNSET** > > 1. The `avail-deno` SDK has been sunset and will not be maintained or upgraded in the future. > > 2. We recommend you switch to `avail-js`. The SDK will work with `deno` out of the box. \ > Just run `deno run --allow-net your-file-name.ts` to run your `avail-js` code with `deno`. 1. Make sure `avail-deno` is installed on your system. You can refer to [Deno's docs](https://docs.deno.com/runtime/manual/) for the same. 2. Create a new Deno JS project by running `deno init` in a directory of your choice, and create a new file named `your-file-name.ts` in the project. 3. The examples in this reference will interact with the Turing testnet of Avail DA, and will use the correspponding endpoint. You can use the [networks page](/docs/da/networks) to find endpoints for mainnet if you need to. #### avail-rust 1. Make sure `rust` and cargo are installed on your system. You can refer to [Rustlang's docs](https://www.rust-lang.org/tools/install) for the same. 2. Create a new Rust project by running: ```bash filename="terminal" name="cmd9" cargo init ``` 3. Paste the following into your `Cargo.toml` file: ```toml showLineNumbers filename="Cargo.toml" name="cmd10" [workspace] [package] name = "your-project-name" edition = "2021" [dependencies] # Use avail-rust v0.1.9 from the `avail-rust` repo avail-rust = { git = "https://github.com/availproject/avail-rust", tag = "v0.1.9" } # Tokio tokio = { version = "1.38.0", features = ["full"] } # dotenvy dotenvy = "0.15.7" ``` > **Warning** > > **Check your rust version** > > 1. Run `rustc --version` to check the version of rust installed on your system. > 2. Some features of the `avail-rust` SDK may not work with older versions of rust. > 3. You can update the Rust version on your system by running `rustup update`. 4. Create a `.env` file in the root of your project by running the following command: ```bash filename="terminal" name="cmd11" touch .env ``` 5. Put in the Seed Phrase of the account you want to use into the `.env` file: ```bash showLineNumbers filename=".env" name="cmd12" SEED="This is a random seed phrase please replace with your own" ``` > **Error** > > **IMPORTANT** > > 1. Please be **VERY CAREFUL** with your seed phrase. > 2. Make sure to add your `.env` file to your `.gitignore` so that it doesn't get pushed anywhere. > 3. While it is good enough to use an `env` file while testing, try to use better practices while deploying to production. #### avail-go 1. Make sure `go` is installed on your system by running the following command in your terminal: ```bash filename="terminal" name="cmd13" go version ``` If not installed, you can refer to [Go's docs](https://golang.org/doc/install) for the same. 2. Create a new Go project by initializing a Go module in a directory of your choice. Run the following command: ```bash filename="terminal" name="cmd14" go mod init your-project-name ``` 3. To install the avail-go-sdk, use the following command to add it to your project: ```bash filename="terminal" name="cmd15" go get github.com/availproject/avail-go-sdk@v0.2.7 ``` 4. To install the `godotenv` package, use the following command: ```bash filename="terminal" name="cmd16" go get github.com/joho/godotenv ``` > **Warning** > > **CHECK YOUR GO VERSION** > > 1. Run `go version` to check the version of go installed on your system. > 2. Some features of the `avail-go-sdk` may not work with older versions of go. > 3. Refer to [Golang's docs](https://go.dev/doc/install) for any questions. 5. Create a `.env` file in the root of your project by running the following command: ```bash filename="terminal" name="cmd17" touch .env ``` 6. Put in the Seed Phrase of the account you want to use into the `.env` file: ```bash showLineNumbers filename=".env" name="cmd18" SEED="This is a random seed phrase please replace with your own" ``` > **Error** > > **IMPORTANT** > > 1. Please be **VERY CAREFUL** with your seed phrase. > 2. Make sure to add your `.env` file to your `.gitignore` so that it doesn't get pushed anywhere. > 3. While it is good enough to use an `env` file while testing, try to use better practices while deploying to production. ### Gas Relay Deprecated > **Warning** > > **Gas Relay has been deprecated.** > This service has been replaced by Turbo DA. Gas Relay endpoints are no longer available. ## What replaced it [Turbo DA](/docs/da/build/turbo-da) is a gasless transaction submission service that provides sub-250ms pre-confirmations for data posted to Avail DA. It replaces the Gas Relay with a credit-based model where you purchase data credits (measured in KB/MB) instead of paying gas fees per transaction. ## How to migrate 1. **Get a Turbo DA account** — sign in at the Turbo DA dashboard and configure your AppID: | | Mainnet | Turing Testnet | | ------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------- | | **Dashboard** | [turbo.availproject.org](https://turbo.availproject.org/) | [staging.turbo.availproject.org](https://staging.turbo.availproject.org/) | | **API** | [turbo-api.availproject.org](https://turbo-api.availproject.org/) | [staging.turbo-api.availproject.org](https://staging.turbo-api.availproject.org/) | 2. **Generate an API key** — from the dashboard, click "Generate new key" and save it securely. Keys are only shown once. 3. **Update your integration** — replace Gas Relay calls with the Turbo DA API. See the [Turbo DA guide](/docs/da/build/turbo-da) for a step-by-step walkthrough or the [Turbo DA API reference](/docs/da/api-reference/avail-turbo-da-api) for endpoint details. ### Interact with DA Interact with Avail DA directly. Start by [getting testnet tokens](/docs/da/build/interact/faucet), then [create an App ID](/docs/da/build/interact/app-id) to begin posting data. - [**Get Testnet Tokens**](/docs/da/build/interact/faucet) — Get AVAIL tokens on the Turing testnet to start experimenting. - [**Create an AppID**](/docs/da/build/interact/app-id) — Register a unique App ID to separate your data submissions on Avail DA. - [**Read & Write Data**](/docs/da/build/interact/read-write-on-avail) — Submit data blobs and read them back using the SDK. - [**Query Balances**](/docs/da/build/interact/query-balances) — Check AVAIL token balances for any account. - [**Transfer Balances**](/docs/da/build/interact/transfer-balances) — Send AVAIL tokens between accounts. ### Rollups Choose a rollup framework and deploy on Avail DA for data availability. ## Optimium - [**OP Stack**](/docs/da/build/rollups/op-stack) — Deploy an OP Stack rollup using Avail DA. - [**Arbitrum Nitro**](/docs/da/build/rollups/arbitrum-nitro) — Deploy an Arbitrum Nitro rollup using Avail DA. ## Validium - [**Polygon zkEVM**](/docs/da/build/rollups/zkevm) — Deploy a Polygon zkEVM validium with Avail DA. - [**Polygon CDK**](/docs/da/build/rollups/cdk) — Deploy a Polygon CDK chain with Avail DA. - [**Madara**](/docs/da/build/rollups/madara) — Deploy a Madara (Starknet) appchain with Avail DA. - [**zkSync**](/docs/da/build/rollups/zksync) — Deploy a zkSync validium with Avail DA. ## Sovereign - [**Cosmos**](/docs/da/build/rollups/cosmos) — Use the Avail DA module for Cosmos SDK chains. ### Turbo DA > **Warning** > > **TURBO DA IS CURRENTLY IN PRIVATE BETA** > Access to Turbo DA is currently limited only to whitelisted users. > If your team is interested in using Turbo DA, please reach out to us at [business@availproject.org](mailto:business@availproject.org) ## Introduction Avail DA today has a block time of 20 seconds, and a finalization time of 2-3 blocks, which is to say about 60 seconds in most cases. While this is more than enough for most use cases, some applications require a faster finality process to power their use cases. Turbo DA is a solution to this problem. With Turbo DA, you can simply post your data to the Turbo DA API, and the service will give you a lightning-fast pre-confirmation in less than 250 milliseconds. Following this, we will make sure your data is eventually posted to Avail DA, with you not needing to do anything else. ## How to get started 1. Every account on Turbo DA needs to buy '*credits*', measured in `KBs/MBs` of data which is the amount of data they can submit to Turbo DA. 2. Turbo DA is a highly versatile service, and allows you to buy credits in exchange for a wide variety of ERC-20 tokens. 3. Follow the steps below to get started: ### Step 1: Reach out to us (This step is only needed while the service is in private beta) If your team is interested in using Turbo DA, please reach out to us at [business@availproject.org](mailto:business@availproject.org) ### Step 2: Sign in to the Turbo DA dashboard Go to the the following dashboard and sign in with your whitelisted account: | | **Mainnet** | **Turing Testnet** | | ------------ | --------------------------------------------------------- | ------------------------------------------------------------------------- | | **Frontend** | [turbo.availproject.org](https://turbo.availproject.org/) | [staging.turbo.availproject.org](https://staging.turbo.availproject.org/) | ### Step 3: Configure your AppID 1. We expect developers building on top of Avail DA to have a specific AppID for their application. 2. Configure this `AppID` in the dashboard, and this is where your data will eventually be posted. > **Note** > > **NOT FAMILIAR WITH APPIDS?** > `AppIDs` are a core concept every developer building on top of Avail DA should be familiar with. > You can go through [this page in our docs for the same](/docs/da/concepts/app-ids). AppID Configuration ### Step 4: Get your API key Click on the `Generate new key` button to generate a new API key. > **Warning** > > **IMPORTANT** > > 1. Every API key will only be shown once on the dashboard, so make sure to copy and save it securely. > 2. You can always delete an existing API key, or generate a new one. API Key Generation ### Step 5: Use the API key to submit data Once you have your API key, feel free to head on over to our [API reference](/docs/da/api-reference/avail-turbo-da-api) to start leveraging the power of Turbo DA. ### VectorX DA verification VectorX is the implementation of Avail's data attestation bridge that is used to bridge data from Avail to the EVM compatible chains in form of data roots commitments. It is implemented as a set of zero-knowledge proof circuits in SP1. \ SP1 is the most feature completed zero-knowledge virtual machine that can prove execution of arbitrary Rust and any other LLVM compiled languages. ## Verify data availability on Ethereum In order to verify data availability on Ethereum it is necessary to first submit data to Avail DA as a data submission(DA) transaction. Data submitted this way will be included in Avail DA's blocks, but not interpreted or executed in any way. You can submit data to Avail DA in a variety of ways, but we recommend using our dedicated SDKs. > **Note** > > You can check out examples on how to submit new data to Avail DA in our [API reference](/docs/da/api-reference/avail-node-api/da-submit-data). \ > You can check out a complete example on submitting data and verifying the data blob inclusion [on our github](https://github.com/availproject/avail/blob/main/avail-js/examples/node-examples/src/validium.ts). ### Submit data to Avail DA To submit new data to Avail DA, you need to sign the extrinsic `dataAvailability.submitData(data)` with the `data` being passed as a param. Once the transaction is included in an Avail DA block and that block is finalized, a `data root` is generated for the entire block, ready to be bridged to Ethereum. ### Bridge data to Ethereum This way your DA transaction becomes a part of the Avail's block `data-root` and it's inclusion can thus be verified. The data submitted to Avail DA is bridged to Ethereum every 360 Avail blocks and the commitment is included in the VectorX contract. VectorX is an implementation of zero-knowledge proof circuits for Vector, Avail's Data Attestation Bridge in [SP1](https://github.com/succinctlabs/sp1-vector). > **Note** > > Deployed VectorX contract for Turing testnet on the Sepolia testnet: [`0xe542db219a7e2b29c7aeaeace242c9a2cd528f96`](https://sepolia.etherscan.io/address/0xe542db219a7e2b29c7aeaeace242c9a2cd528f96). \ > Deployed VectorX contract for Avail mainnet on the Ethereum network: [`0x02993cdC11213985b9B13224f3aF289F03bf298d`](https://etherscan.io/address/0x02993cdC11213985b9B13224f3aF289F03bf298d). \ > Deployed VectorX contract for the Holesky network [`0x8a48b5184dEc29E7276BF74d1C1d30d032F31e19`](https://holesky.etherscan.io/address/0x8a48b5184dEc29E7276BF74d1C1d30d032F31e19) ### Verify data availability on Ethereum When the data root is bridged to the Ethereum network, it is possible to query for the inclusion proof(Merkle proof) using the `bridge-api` deployed for Turing testnet. > **Note** > > You can find detailed documentation on our `bridge-API` in our [API reference](/docs/da/api-reference/avail-bridge-api). > **Note** > > By submitting a Merkle proof to the verification contract it is possible to verify if a piece of data is available on Avail DA. > > A merkle proof is a list of hashes that can be used to prove that the given leaf is a member of the Merkle tree. An example of submitting a proof to the bridge verification contract > deployed on Sepolia network for Turing ([`0x967F7DdC4ec508462231849AE81eeaa68Ad01389`](https://sepolia.etherscan.io/address/0x967F7DdC4ec508462231849AE81eeaa68Ad01389)) > and Ethereum mainnet ([`0x054fd961708d8e2b9c10a63f6157c74458889f0a`](https://etherscan.io/address/0x054fd961708d8e2b9c10a63f6157c74458889f0a)) > can be done by calling `verifyBlobLeaf` function. > This will call deployed contracts function `verificationContract.verifyBlobLeaf(merkleProofInput)` > and return `true` or `false` depending on the provided proof. ### What are App IDs? ## Introduction As a general-purpose base layer, Avail is designed to support many modular chains at the same time, providing consensus and data availability to all of them simultaneously. How does this work? Avail headers contain an index that allows a given modular chain (or "application" in Avail terminology) to determine and download *only* the sections of a block that have data for that particular application. This has significant benefits, including: * Modular applications are mainly unaffected by other uses of the base layer at the same time. * Block sizes can increase without requiring applications to fetch more data because they don't need to fetch the whole block, only what's relevant to them. \ This filtering is done using the "application id" (AppId). Data availability sampling is still done on the entire block, however--this is the process where clients sample tiny parts of the block at random to verify availability. ### Consider a random block on Avail DA It might contain data blobs from a variety of different rollups pertaining to their different execution environments. Think of the EVM, the SVM, Stackr, ZKsync chains, OP stack, and many more. \ If all of this data is randomly strewn about in a block, it would be tedious for a rollup to parse through all of it just to fetch the data it needs.

random block on Avail DA

### Now think of the same data neatly arranged into its own sections But what if all of that same data in the same block was organised into different sections, stored alongside its peers. Each of these *'sections'* would be identified by an `AppID`. \ A developer now does not need to parse through the entire block to find the data they need, they can simply query data from the `AppID` they are interested in.

random data arranged neatly in Avail DA block

### These *'sections'* are flexible All of the rollups running on Avail DA probably won't submit data in all of the blocks. Thus, it is likely some `AppIDs` will be empty in some blocks. \ On the flipside, some rollups might need to submit more data than usual in a particular block. \ None of this is an issue on Avail DA, the individual block builds as needed in the moment.

AppIDs on Avail DA are flexible

## Structure of an App ID Each `appID` consists of 3 fields: * `key`: A string that is the name of the `appID`. Each `appID` should have a unique name. * `owner`: The address of the account that created the `appID`. A single address can create multiple `AppIDs`. * `id`: The unique integer index of the `appID`. It is incremented by 1 every time a new `appID` is created and is automatically assigned. ## Spam and security * The `key` and `id` fields of every `appID` are unique. If you try to create an `appID` with the same `key` as an existing one, the operation will fail. * **Anyone can submit any sort of data to any `appID` regardless of whether or not they created it.** \ This is not an attack vector. Avail DA is a DA layer, not an execution environment -- it is not concerned with the validity of the data being submitted, only with its availability. Any app or execution layer building on top of Avail DA can set up rules to filter out unwanted data submissions. For example, they could require that only data submitted with a particular signature is accepted, treating all other submissions as spam. > **Note** > > **Ready to create your own App ID?** > > * **Via the explorer:** Follow our [explorer guide](/docs/da/user-guides/explorer#how-to-register-my-own-appid) to create one through the UI. > * **Programmatically:** Use our [SDK](/docs/da/build/interact/app-id) for programmatic App ID creation. > * **API reference:** See the [createApplicationKey](/docs/da/api-reference/avail-node-api/da-create-application-key) API docs. > > Data submissions to App IDs incur fees -- learn more about [how transaction pricing works](/docs/da/concepts/tx-pricing). ### Using the Explorer Avail DA has two block explorers that let you inspect on-chain activity — blocks, extrinsics (transactions), validators, staking, and data submissions. Each is suited to different needs. ## Explorers at a glance | | **Subscan** | **Avail Apps (AvailApps)** | | ------------------ | ----------------------------------------------------------- | ------------------------------------------------------------------------------- | | **Best for** | Browsing blocks, transactions, accounts, and staking data | Interacting with the chain — submitting extrinsics, querying state, governance | | **Mainnet** | [avail.subscan.io](https://avail.subscan.io/) | [mainnet.explorer.availproject.org](https://mainnet.explorer.availproject.org/) | | **Turing Testnet** | [avail-turing.subscan.io](https://avail-turing.subscan.io/) | [turing.explorer.availproject.org](https://turing.explorer.availproject.org/) | | **Interface** | Polished read-only explorer with search and filtering | Polkadot JS-based UI with full chain interaction | ### When to use Subscan Subscan is the best starting point for most users. Use it to: * Look up a specific block, extrinsic, or account * View validator performance and staking distributions * Track data submission transactions by App ID * Get a quick overview of network activity ### When to use Avail Apps Avail Apps (a fork of Polkadot JS Apps) gives you direct access to the chain's runtime. Use it to: * Submit extrinsics (transactions) directly from the UI * Query chain state and storage * Participate in governance * Register an [App ID](/docs/da/concepts/app-ids) * Inspect the `submitDataFeeModifier` and other runtime constants ## What you can look up * **Blocks** — View block contents, including which App IDs have data in a given block * **Extrinsics** — Inspect individual transactions, their parameters, and results * **Data submissions** — See the raw data blobs submitted by rollups under each App ID * **Validators** — Check the active validator set, their commission rates, and performance * **Accounts** — Look up balances, staking info, and transaction history > **Note** > > **Want a hands-on walkthrough?** > > See the [Explorer user guide](/docs/da/user-guides/explorer) for step-by-step instructions on common tasks like looking up transactions, registering App IDs, and checking validator status. ### How Avail DA Works Avail DA's core job is to guarantee that data posted by rollups is available for anyone to retrieve and verify. It achieves this through a pipeline of cryptographic techniques and a consensus mechanism designed specifically for this purpose. ## Block data lifecycle When a rollup submits data to Avail, it goes through this pipeline: 1. **Data submission** — The rollup posts transaction data via a `submitData` extrinsic, tagged with its [App ID](/docs/da/concepts/app-ids). 2. **Matrix construction** — The block data is chunked and arranged into a 2D matrix of equal-sized cells. 3. **Erasure coding** — Each row of the matrix is extended using Reed-Solomon erasure codes, adding redundancy. 4. **KZG commitments** — Each row is committed to using KZG polynomial commitments. These commitments are included in the block header. 5. **Consensus** — Validators attest to the block header (which contains the commitments), finalizing it. 6. **Data availability sampling** — Light clients randomly sample cells from the matrix to verify the data is available. ## Erasure coding Erasure coding spreads data across redundant "shards" so that the original data can be reconstructed even if some shards are missing. In Avail, each row of the block data matrix is erasure-coded, effectively doubling its size. This matters because a malicious block producer trying to hide even a single transaction would need to withhold a large portion of the block. Random sampling by light clients becomes far more likely to catch the gap. Without erasure coding, a bad actor could hide a small piece of data that sampling might miss. With it, any attempt to hide data requires withholding so much that it's nearly impossible to evade detection. ## KZG polynomial commitments Each row of the erasure-coded matrix is committed to using KZG commitments. These are compact cryptographic proofs included in every block header that provide two guarantees: 1. **Binding** — It's computationally infeasible to produce a commitment that matches incorrect data. If the commitment is valid, the data is correct. 2. **Efficient verification** — A light client can verify that any individual cell belongs to the committed row without downloading the full row. This is what makes cell-level sampling practical. Together with erasure coding, KZG commitments mean that verifying a single cell proves both that the cell data is correct and that it belongs to the committed block data. ## Data availability sampling (DAS) DAS is how light clients verify that block data is available without downloading entire blocks. The process works like this: 1. A light client receives a new finalized block header containing KZG commitments. 2. It randomly selects a set of cells from the block's data matrix. 3. It retrieves those cells — first from the peer-to-peer DHT network, then via RPC if needed. 4. It verifies each cell against the KZG commitment in the header. 5. It calculates a **confidence score** — the probability that the full block data is available given the number of cells successfully verified. With enough samples (a small constant number), a light client achieves near-100% confidence that the entire block is available. This is a key property of Avail: **you don't need a full node to verify data availability**. A light client running on consumer hardware can do it. > **Note** > > Light clients that verify cells also re-share them on the peer-to-peer network, increasing overall data availability for the network. The more light clients sampling, the stronger the DA guarantee becomes. ## Consensus: how blocks are finalized Avail uses **Nominated Proof of Stake (NPoS)** for validator selection, combined with two Substrate-based protocols for block production and finality: | Protocol | Role | | ---------------------------------------------------------------------- | ------------------------------------------------------------------ | | **BABE** (Blind Assignment for Blockchain Extension) | Block production — validators are assigned slots to produce blocks | | **GRANDPA** (GHOST-based Recursive Ancestor Deriving Prefix Agreement) | Finality — validators vote to finalize chains of blocks | Validators in Avail don't execute transactions. They attest that data has been correctly packaged into blocks with valid KZG commitments. This is a lighter workload than execution-based chains, which is why Avail can support larger block sizes without proportionally increasing validator requirements. A supermajority of validators must sign off on a block header (which includes the KZG commitments and a Merkle root of the data) for it to be finalized via GRANDPA. Once finalized, the data is considered available and immutable. > **Note** > > **Next steps** > > * Understand how rollup data is organized with [App IDs](/docs/da/concepts/app-ids). > * Learn how [transaction pricing](/docs/da/concepts/tx-pricing) works for data submissions. > * Run your own [light client](/docs/da/operate/run-a-light-client) to participate in DAS. > * Become a [validator](/docs/da/operate/become-a-validator) on the Avail network. ### How Transaction Pricing Works Every extrinsic (transaction) executed on Avail costs a certain amount of `AVAIL` tokens. These fees vary for different extrinsics and are determined primarily by two considerations: 1. The amount of processing power required to include the transaction in the chain. 2. The amount of storage required to store the transaction on-chain. Avail's pricing formula is designed to keep transacting on-chain feasible while also making it expensive to spam the network. ## Terms you need to know 1. **Base fee**: The minimum base amount attached to every single transaction. This is the constant whose current value is currently `0.124 AVAIL`. 2. **Weight fee**: This fee is proportional to the amount of computation required to add the transaction to the network. 3. **Length fee**: This fee is proportional to the encoded length of the transaction, essentially the amount of space it consumes in the block. 4. **Congestion fee**: A multiplier applied to the Weight fee based on block fullness of previous blocks (Notice blocks not block, because `fee_multiplier` is a function of both the current fee multiplier and the fullness of the preceding block. A kind of guard against sudden rise/fall of fee). 5. **Tip (optional)**: This is an optional fee that can be attached to a transaction to incentivize validators. ## Fees calculation for non-DA transactions The formula for the final transaction fee for most transactions looks like this: ``` Weight fee = [Congestion multiplier * Weight of transaction] Final fee = Base fee + Length fee + Weight fee + Tip(optional) ``` Most transactions like balance transfers and proxy creation have predictable fees — transferring `1` AVAIL requires the same computation as transferring `1000` AVAIL, so the Weight fee stays constant. This changes for transactions that post new data to the network, where the size of the data directly affects the cost. ## Fees calculation for DA transactions The formula for the final transaction fee for data availability transactions looks like this: ``` Weight fee = [Congestion multiplier * Weight of transaction]*[submitDataFeeModifier] Final fee = Base fee + Length fee + Weight fee + Tip(optional) ``` ### What's different? #### `submitDataFeeModifier` Posting new data to the chain is a core component of the Avail network. To ensure the fees for doing so remain viable, the `submitDataFeeModifier` can be adjusted when needed after going through [Avail's governance process](/docs/da/user-guides/staking-governance/governance-on-avail). This multiplier is used to adjust the `Weight fee` component of the final fee for all `dataAvailability_submitData` transactions. > **Note** > > To query the current value of the `submitDataFeeModifier`: > > 1. Go to the [chainstate page of the Avail explorer](https://explorer.availproject.org/#/chainstate). > 2. Query the `dataAvailability_submitDataFeeModifier` method. #### Significance of the data input For most extrinsics on Avail, the raw size of the input parameters doesn't matter much. DA transactions are different — the size of the data being posted has a direct impact on both fee components: The **Length fee** scales with the encoded size of the data, since larger submissions consume more block space. The **Weight fee** also increases because generating KZG commitments for the data requires more computation as the data grows. In short, larger data submissions cost more in both dimensions — storage and compute. #### Worked example Consider a `submitData` transaction posting a 512-byte data blob under normal network conditions (no congestion): ``` Base fee: 0.124 AVAIL (constant) Length fee: proportional to ~512 bytes of encoded data Weight fee: [1.0 * weight] * submitDataFeeModifier Tip: 0 (optional) ``` The exact fee depends on the current `submitDataFeeModifier` and congestion multiplier, both of which can be queried on-chain. Under low congestion with a neutral modifier, a 512-byte submission typically costs a fraction of an AVAIL token. Larger submissions (e.g. 128 KB) cost proportionally more due to the increased length and commitment generation weight. > **Note** > > **Related concepts** > > * Learn about [App IDs](/docs/da/concepts/app-ids), which are used to organize data submissions on the network. > * Understand [how Avail DA works](/docs/da/concepts/how-avail-da-works) — including KZG commitments that drive the Weight fee. > * See [Networks & Endpoints](/docs/da/networks) for network details and contract addresses. ### What is Avail DA? Rollups need somewhere to post their transaction data so that anyone can verify it's available. Traditionally this means posting to Ethereum L1, but that's expensive and doesn't scale — every byte of calldata competes for the same limited block space. Avail DA is a purpose-built data availability layer that solves this. Instead of piggybacking on a general-purpose L1, rollups post their data to Avail, where it's ordered, committed to with cryptographic proofs, and made available for verification — all without Avail needing to execute any of it. ## How Avail fits in the modular stack A modular blockchain separates its core functions into specialized layers: | Layer | Responsibility | Example | | --------------------- | ---------------------------------------------------------------- | ------------------------------------------------------- | | **Execution** | Process transactions and update state | Your rollup (OP Stack, Arbitrum Orbit, ZK chains, etc.) | | **Settlement** | Verify execution proofs and resolve disputes | Ethereum | | **Data Availability** | Guarantee that transaction data was published and is retrievable | **Avail DA** | Avail sits at the DA layer. It doesn't execute transactions, validate state transitions, or handle settlement. It does one thing — ensures the data your rollup posts is available — and it does it well. ## What makes Avail DA different ### No execution overhead Avail validators don't re-execute your transactions. They attest that data has been correctly published and committed to. This means Avail can support much larger blocks than chains where validators must process every transaction. ### Validity proofs, not just attestations Avail uses **KZG polynomial commitments** to generate validity proofs for block data. These proofs are included in every block header, allowing anyone to verify data correctness without downloading the entire block. ### Data availability sampling (DAS) Light clients on Avail randomly sample small portions of each block to probabilistically verify that the full data is available. Combined with erasure coding, this gives near-100% confidence with minimal bandwidth. This means even devices with limited resources can verify DA without trusting a full node. ### App IDs for data isolation Each application on Avail gets its own [App ID](/docs/da/concepts/app-ids). Your rollup only needs to download the data posted under its App ID — not the entire block. Other chains using Avail at the same time don't affect your throughput or costs. ## Who uses Avail DA Avail DA is designed for **rollup developers and infrastructure teams** who need: * A scalable DA layer that won't bottleneck their rollup's throughput * Cryptographic guarantees (not just committee attestations) that data is available * A chain-agnostic solution that works with any execution environment — EVM, SVM, custom VMs Rollup frameworks like OP Stack, Arbitrum Orbit, ZKsync, Madara, and others can integrate Avail DA as their data availability backend. > **Note** > > **Next steps** > > * Learn [how Avail DA works](/docs/da/concepts/how-avail-da-works) under the hood — DAS, erasure coding, and consensus. > * Ready to build? Jump to the [Build section](/docs/da/build) to integrate your rollup with Avail DA. > * See [Networks & Endpoints](/docs/da/networks) for RPC URLs and contract addresses. ### Become a Validator Become an Avail DA validator. These guides walk you through the full lifecycle — follow them in order from Basics through Monitoring. - [**Basics**](/docs/da/operate/become-a-validator/basics) — Requirements, economics, and what it means to validate on Avail DA. - [**Simple Deployment**](/docs/da/operate/become-a-validator/deployment) — Deploy your validator node with a straightforward setup. - [**Session Keys**](/docs/da/operate/become-a-validator/session-keys) — Generate and set session keys for block production. - [**Stake Your Validator**](/docs/da/operate/become-a-validator/stake-your-validator) — Bond AVAIL tokens and register your validator on-chain. - [**Backup Your Validator**](/docs/da/operate/become-a-validator/backup-your-validator) — Back up keys and state to protect against data loss. - [**Upgrade Your Validator**](/docs/da/operate/become-a-validator/upgrade-your-validator) — Upgrade your node software without downtime. - [**Monitor Your Validator**](/docs/da/operate/become-a-validator/monitor-your-validator) — Track performance, uptime, and on-chain status. - [**Chill Your Validator**](/docs/da/operate/become-a-validator/chill-your-validator) — Temporarily take your validator offline without unbonding. ### Deployment Options Different service providers offer hosted deployment options for Avail. These platforms simplify the management of blockchain infrastructure by providing cloud-based services and comprehensive support for network deployment and maintenance. | Service | Description | Deployment Type | Documentation | | ------- | --------------------------------------------------------------------------------------------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | Spheron | Cloud-based, decentralized, infrastructure services for blockchain applications, offering simplicity and scalability. | Hosted | [Deploy and Operate an Avail Testnet Validator](https://blog.spheron.network/deploy-an-avail-node-in-minutes-using-spheron-compute) | ### Node Types ## Introduction While Avail diverges from conventional blockchain frameworks to concentrate on modular solutions tailored for data availability, it continues to utilize a diverse array of node types. These nodes differ in their functions, storage needs, and levels of engagement within the network. ## Node Types Comparison **Note:** Infrastructure providers can host all types of Avail nodes. | Node Type | Storage Requirement | Network Role | Special Features | Use Case | Typically Hosted By | | --------------- | ------------------- | ------------ | ---------------- | ---------------------------------------- | ------------------------------------------------------------- | | Light Clients | Low | Interaction | Minimal Storage | Quick Queries, Low-resource Environments | End users in low-resource environments | | Full Nodes | Moderate | Core | Network Access | Transaction Verification, Data Retrieval | Regular network participants, those involved in verification | | Validator Nodes | Moderate | Core | Block Production | Network Security, Governance | Trusted entities, elected participants, staked node providers | | RPC Nodes | Moderate | Gateway | API Exposure | Development, Remote Access | Developers, entities requiring remote network access | ## Overview of Node Types ### Light Clients Light clients allow users to interact with the blockchain without downloading the entire transaction history. They rely on a trusted set of nodes for the data needed to engage with the network. ### Full Nodes Full nodes maintain the blockchain's current state but do not store its entire history. Optimized for quick access to current data, they are ideal for tasks like transaction verification. ### Validator Nodes Validator nodes are specialized full nodes that participate in block production and network governance. They are staked to ensure network security and integrity. ### RPC Nodes RPC nodes expose an API for remote interactions, serving as a gateway for developers and external clients to engage with the Avail network. ## Next Steps Now that you have a comprehensive understanding of the various node types within the Avail network, it's recommended to take your first step by setting up a Light Client. Before you begin, make sure to review the [System Requirements guide](/docs/da/operate/run-a-full-node/overview). Once you're ready, you can proceed to the [Light Client Deployment guide](/docs/da/operate/run-a-light-client/light-client) to get started. > Light Clients provide an accessible entry point to the Avail network, enabling quick interactions without storing the full blockchain. Ideal for newcomers, they play an integral role in maintaining a robust data availability layer. ### Full Node Run a full Avail node for complete block storage and network participation. Read the overview for requirements, then follow the setup guide. - [**Overview**](/docs/da/operate/run-a-full-node/overview) — Architecture, hardware requirements, and what a full node does on the network. - [**Run an Avail Node**](/docs/da/operate/run-a-full-node/full-node) — Step-by-step guide to install and run a full Avail node. ### Light Client Run an Avail light client — the easiest way to verify data availability without storing full blocks. Read the overview first, then follow the setup guide. - [**Overview**](/docs/da/operate/run-a-light-client/overview) — How light clients sample and verify data availability on Avail DA. - [**Run a Light Client**](/docs/da/operate/run-a-light-client/light-client) — Step-by-step guide to install and run an Avail light client. ### Accounts ## Introduction This guide will walk you through two different ways of creating an account on Avail, while also providing insights into the account specifications and formats. ### Seed Phrases Before creating an account, it's essential to understand [seed phrases](https://en.wikipedia.org/wiki/Cryptocurrency_wallet). During the account creation process, you'll receive a seed phrase—a series of words that can be used to recover your account. > **Error** > > SEED PHRASE SECURITY > > NEVER EVER share your seed phrase with anyone and keep it in a secure location. Anyone with access to your seed phrase can gain control of your account. ## Creating an Account on Avail DA In this guide, we will walk you through two different ways of creating an account on Avail DA. 1. **Using a compatible wallet**: You can create an account by using wallets like [SubWallet](https://www.subwallet.app/), [Talisman](https://www.talisman.xyz/), [PolkadotJS](https://polkadot.js.org/), [Nova Wallet](https://novawallet.io/) and others. This guide will be using Subwallet as an example. 2. **Using the Explorer**: Advanced users can also create an account straight from the explorer. #### Subwallet 1. Go to [Subwallet.app](https://www.subwallet.app/) and install their browser extension. Once installed, you should se a few different options to get started. We will create an account from scratch, although you can import existing accounts too. 2. Subwallet will prompt you to set up a password to secure access to the accounts in the wallet. Please note that this password **DOES NOT** control the actual on-chain account, and is merely used to open the wallet extension. 3. Next, read through and agree with all of Subwallet's conditions to get the Seed Phrase of your Avail account. 4. You will be shown your seed phrase. **Make sure to write it down and store it in a safe place**. > **Warning** > > Please note that this seed phrase is exposed only one time at the time of account creation by Subwallet. > Make sure to store it in a safe place as it is the only way to recover your account. 5. Open the `networks` menu from the top-right. You can configure which networks you want displayed by Subwallet from here. 6. Search for Avail testnets either by name or by token symbol. Make sure the network is toggled on. > **Note** > > Please note `Avail` is short-hand for Avail DA mainnet, while the other option connects you to the Turing testnet. > You can choose if you want to connect to one or both of them. 7. Next go to your extension's homepage and click on the `Get address` button. Again, search for Avail testnets by name or token symbol, and click on the `copy address` button. #### PolkadotJS or Talisman 1. To start with setting up your PolkadotJS wallet, you can go to the [PolkadotJS extension homepage](https://polkadot.js.org/extension/) to get started. 2. To get started with Talisman, you can go to [Talisman's docs page](https://docs.talisman.xyz/talisman/start/installing-talisman) that will show you how to set up a wallet with Talisman. #### Klever Wallet 1. Go to the [Apple Store](https://apps.apple.com/tt/app/klever-wallet-bitcoin-crypto/id1615064243), [Google Play](https://play.google.com/store/apps/details?id=finance.klever.bitcoin.wallet\&pcampaignid=web_share) or Huawei Store and install the Klever Wallet app. Once installed, you should see two different options to get started. We will create a new wallet from scratch, although you can restore an existing wallet too. 2. Klever Wallet will prompt you to set up a PIN to secure access to the accounts in the wallet. First you will need to set the PIN and you will need to confirm the PIN. 3. You can make your wallet even more secure by activating biometric/faceID authentication. 4. Done! Your wallet is created. You can choose to backup your seeds now or later. We’ll do it now like Klever recommended. 5. Read the security warnings and by clicking on the I Agree button you’ll see your seeds. It’s really important to write your seeds in exactly the same order as shown and keep them in a safe place. 6. Now you can write your seeds that you have written before in exactly the same order. 7. In your portfolio, click on + Tokens button and search for Avail. You just need to activate it and you’ll be able to use the Avail blockchain inside Klever Wallet. #### Nova Wallet 1. Go to [novawallet.io](https://novawallet.io/) and install the application from either the Google Play or Apple App Store. Once installed, you will see a few different options to either create a new account, import an existing account, or connect a hardware wallet. In this case, let’s create a new account. 2. Select “Create a new wallet”. 3. Input your wallet’s nickname and select “Continue”. 4. Review the pop-up alert and then select “I understand”. 5. Make a copy of your Mnemonic Passphrase. Make sure to write it down and store it in a safe place, then select “Continue”. 6. Input your Mnemonic Passphrase in the correct order and then select “Continue”. 7. You have now created your wallet in Nova Wallet and can access the Avail ecosystem! #### Using the explorer > **Warning** > > Please note that you won't be able to use the account created on the explorer to claim your rewards. 1. Navigate to the [Avail Explorer](https://explorer.availproject.org/). 2. Once on the explorer, go to `Accounts -> Accounts` in the navigation bar. 3. Click on the `+Account` button on the right-hand side to initiate the account creation process.

4. Follow the on-screen instructions to complete the account creation process. Make sure to securely store your seed phrase for future reference. 5. Upon completion, a JSON file containing your account information will be downloaded to your file system. You may be prompted to grant browser permissions for the download. #### What is the JSON File? The JSON file serves as a backup for your account and contains all the necessary information to recover it. It is encrypted with a password that you set during the account creation process. > Backup and Recovery > Always keep your JSON file in a secure and offline location. Losing this file and your password could result in the loss of your assets. > **Warning** > > Please note that Avail DA is a modular blockchain built on top of the Substrate framework. due to how Substrate works, > the exact on-chain address of your account may vary from one chain to another. > Make sure to always double-check the address you are using. Avail addresses, for example will always begin with the number **`5`**. > **Warning** > > UPDATE METADATA > Sometimes when the chain undergoes upgrades, the underlying metadata within your wallets/extensions may become outdated. > Not updating them might result in transaction signatures failing. > You can update your metadata, if needed, using the [AvailApps explorer](https://explorer.availproject.org/#/settings/metadata). ## Next Steps Congratulations on successfully creating and managing your Avail account! Remember to always safeguard your account details, JSON file, and seed phrase to ensure the security of your assets. Ready to explore further? Navigate to the next guide to learn [how to use the Avail Explorer](/docs/da/user-guides/explorer) and get hands-on experience with the network. ### Ledger Fund Recovery ## What's the problem? 1. The `Avail` ledger app derives a different set of addresses as compared to the `Polkadot` ledger app for the same seed phrase. 2. This means while the addresses derived on the `Polkadot` ledger app will work on `Avail`, the `Polkadot` ledger app will not allow users to sign transactions on the `Avail` network. 3. To solve this problem we have created the `Avail recovery` app for ledger devices. 4. This new app will derive the same set of addresses as the `Polkadot-ledger` app and allows users to sign transactions on the `Avail` network, thus giving users access to these funds. > **Note** > > **LOOKING FOR INSTRUCTIONS WITH DIFFERENT WALLETS?** > > 1. The following set of instructions are written using subwallet. > 2. But you can use any other wallet that supports ledger devices just as well. > 3. We also have a guide for [setting up a ledger account with Talisman in our docs here](/docs/da/user-guides/ledger-avail#add-your-ledger-account-to-an-extension-wallet) ## How to use the `Avail recovery` app? ### Make sure the `Avail recovery` app on your ledger device using the Ledger live app. > **Note** > > **NOTE:** > The `Avail recovery` app is available on the ledger live app only in the `Developer mode`. > > 1. Go to `My Ledger` section, and find the settings ⚙️ icon on the top right section. > 2. Head to `Experimental Features` and switch on `Developer Mode`. > 3. Move back to `My Ledger`, and search `Avail Recovery` in the search bar. ### Click on the accounts dropdown in your wallet extension ### Click on `Attach account` ### Select the `Connect a ledger device` option ### Search for the `Avail recovery` app and click on `Connect` ### You can now select as many or as few of your ledger accounts to your Subwallet extension wallet > **Note** > > **NOT ABLE TO SELECT YOUR ACCOUNTS?** > > 1. It is important to remember that the `Avail recovery` app will derive the same set of addresses as the `Polkadot` ledger app to give you access to your funds. > 2. This means if your wallet already has that same ledger address connected via the `polkadot` ledger app, you will not be able to import it once again via the `avail recovery` app. > 3. To get around this, you can temporarily delete the polkadot ledger address from your wallet and then re-add it via the `avail recovery` app. > 4. This does not remove the address from your ledger device, just disconnects it from your wallet. > 5. Now you should be able to import the same address via the `avail recovery` app. ### Multisigs You can use the [avail-apps](https://explorer.availproject.org/#/accounts) explorer to set up and start using a multisig wallet on Avail DA. This guide will show you how to do so. > **Note** > > **PREREQUISITES** > The only prerequisite is that you have access to one or more Avail DA accounts. > Refer to our docs on [setting up an Avail wallet](/docs/da/user-guides/accounts) for more details if needed ## Create a multisig wallet on Avail DA ### Import the signatory accounts You need to import into the explorer all the accounts you want added as signatories to the multisig. There are two ways to do this: #### Via address book 1. Go to the [`addresses`](https://explorer.availproject.org/#/addresses) page of the explorer. 2. Click on `Add contact` and save any addresses you want. #### Import a json file 1. Create a json file with all the Avail DA addresses you want to import. The syntax is as follows: ```json [ "add1", "add2", "add3" ] ``` 2. Save the file. This will be of use later. > **Note** > > This method is suitable if you have a large number of addresses to import. ### Start setting up the multisig Go to the [accounts page of the avail-apps explorer](https://explorer.availproject.org/#/accounts), and click on `Multisig`. This will give you a UI interface that will allow you to configure your multisig wallet. > **Note** > > DOUBLE CHECK > Please note that a multisig account created on one network won't be created automatically on another. This > tutorial is based on he Turing testnet, but will work just as well for Avail DA mainnet too. ### Configure the multisig 1. Select all the signatories you want to include in the multisig wallet. You can do so either by: * Importing addresses from your address book, or, * by uploading the json file outlined in `step 1`. 2. Select the `threshold` value for the multisig. It represents the minimum number of addresses that need to approve a transaction for it to be executed. A `threshold` value of `2` in our case would mean that any `2` of the `3` signatories can perform a transaction from the multisig. 3. Choose an appropriate name for the multisig. 4. Click on `Create`. > **Note** > > **BUT WHAT OF OTHER SIGNATORIES?** > An obvious question that pops up is how will other signatories import the multisig wallet into the avail-apps > explorer on their own machine? > Due to the way the `multisig` pallet works on Avail DA, a multisig derived from the same set of addresses and the same `threshold` value > will always have the same address. > Thus, all signatories can simply create a multisig on their machine with addresses of all the other signatories along with a constant `threshold value` to derive the same '*multisig address*'. > Alternatively, a single json file with all signatories can be created and shared among all signatories. > **Note** > > The next steps will take you through using your multisig wallet for the first time. Please send some tokens to > the multisig's address before proceeding. ## Use a multisig wallet on Avail DA ### Create a transaction to transfer funds You should now be able to see your new multisig account created under a seperate category on the [accounts page](https://explorer.availproject.org/#/accounts). Click on `send` to start creating a new transaction. Enter the recipient and the amount to transfer, and click on `Make Transfer`. ### Sign and submit the transaction You will now be able to sign a `balances.transferKeepAlive` transaction from the multisig account. This extrinsic allows you to transfer funds from one account to another. 1. A transaction for a multisig can only be created via an approved signatory. Choose one from the `multisig signatory` dropdown. > **Warning** > > PLEASE NOTE > You can only sign a transaction for the multisig from the signatory accounts you have access to. > If you don't have access to an authorised signatory, you can't create, approve, or reject a transaction > for the multisig. 2. Copy the hexadecimal value of the `multisig call data`. This value will be needed later on. 3. Make sure that the `sign and submit` on the bottom-left option is checked. Finally, click on the `Sign and Submit` button on the bottom right. ### Approve and/or execute the transaction Now that a transaction has been created, other signatories have the choice to either: 1. Approve the transaction, or, 2. Reject the transaction. You will see a pink icon next to your multisig wallet that indicates a pending transaction. Click on 'View Pending Transactions' to take a look. Click on `approval type` to simply approve or reject the transaction. 1. Our `threshold` value was set at `2`, and we already have one approval in form of the signatory that originally created the transaction. 2. Thus, an approval by just one more authorised signatory will execute the transaction that will transfer `10 AVAIL` to the recipient. But what if you simply want to approve the transaction without executing it? Avail DA's multisig implementation allows for this functionality too. Let us say you are the final signatory whose approval will mean the transaction has enough approvals to be executed. But you don't want to execute the transaction just yet. *You only want to approve it, and let some other signatory execute it later on.* #### Approve 1. If a signatory wants to approve the transaction without executing it, they don't need the `multisig call data` value. 2. Make sure the `multisig message with call` button is unchecked, and click on `Approve`. 3. Then, click on `Sign and Submit` and execute the transaction. > **Note** > > **POINTS TO NOTE** > > 1. After the `threshold` value of minimum number of approvals has been met, any signatory can execute the transaction. > 2. You cannot execute the transaction without the `multisig call data` value. #### Approve and Execute 3. Paste the `multisig call data` you copied in the second step into the empty column. 4. Click on `Approve`. 5. Click on `Sign and Submit`. 6. Depending on how you have connected the signatory account to the `avail-apps` UI (ledger seed phrase, wallet extension), you might have different transaction approval interfaces. But once you approve it, funds should be successfully transferred from the multisig wallet. > **Note** > > Needless to say, you will, as a signatory, be able to execute the transaction only if you are the last signatory required to meet the `threshold` value. {/* ## 2nd way to use a multisig wallet on Avail DA (for advanced users) Let us go through the same process as before, i.e., executing a transaction from our multisig wallet to transfer funds, but using the `extrinsics` tab instead. */} ### MetaMask Snap ## Introduction MetaMask is one of the most popular wallets for Ethereum and other EVM-compatible blockchains out there. MetaMask Snaps is an open source system that allows developers to create a custom '*Snap*' that can be installed into a user's MetaMask wallet to extend it's functionality for different chains. You can check out [MetaMask website](https://metamask.io/snaps) and [MetaMask docs](https://docs.metamask.io/snaps/) for more information. The Avail snap will allow you to easily interact with Avail DA from within your MetaMask wallet. We are actively working on adding more features to the Avail Snap, so stay tuned for updates. ## Using the Avail Snap ### Install the Avail Snap Go to [the official MetaMask snaps store](https://snaps.metamask.io/snap/npm/avail-project/avail-snap/), and click on '*Add to MetaMask*'. Grant the required permissions to the Avail Snap to complete the installation process. Once the installation is complete, your screen should look like this: ### Use the Avail Snap > **Note** > > The Avail Snap generates an address for you based on the seed phrase embedded into your > MetaMask wallet. Thus, if you transfer the same wallet to a new system and install > the Avail Snap again, you will derive the same address. Go to [snap.availproject.org](https://snap.availproject.org/), which is a UI interface that allows you to conveniently use the Avail Snap. Connect your metamask extension to this webpage by clicking on '*Connect with MetaMask*'. Once connected, you will see your derived address and its balance on screen: > **Note** > > **PLEASE NOTE** > > 1. You will need to send some AVAIL tokens to your new address before being able to make a transaction with it. > 2. You can toggle between Avail DA testnet and mainnet by using the dropdown on the top right. Make sure to select the correct network. ### Make a transaction Click on *'send'* , enter an amount and a recipient, then approve a transaction on Avail DA from within your MetaMask wallet. > **Note** > > THE BRIDGE UI > Please note that the `bridge` button takes you to a different interface that you can > use to transfer tokens between Avail DA and Ethereum. > The bridge UI does not yet support the Avail Snap. ## FAQs ### Why should I use the Avail Snap at all? MetaMask is an EVM-compatible wallet that supports 20-byte hexadecimal addresses derived from seed phrases and/or private keys. Avail DA meanwhile uses the [SS58 address format](https://docs.substrate.io/learn/accounts-addresses-keys/#address-encoding-and-chain-specific-addresses). The Avail Snap makes it possible for you to conveniently interact with Avail DA from within your MetaMask wallet. ### How does the Avail Snap work? [MetaMask Snaps](https://metamask.io/snaps/) is an open source solution designed to extend MetaMask's functionality. The Avail Snap derives an SS58 address using your MetaMask credentials and allows you to sign transactions on Avail DA through an easy-to-use UI interface. ### What if I switch to a new system? The Avail Snap generates an address for you based on the secret recovery phrase in your MetaMask wallet. Thus, if you transfer the same wallet to a new system and install the Avail Snap again, you will derive the same address. ### Are my keys safe with the Avail Snap? Please note that the Avail Snap does not store your private keys. ### Has the Avail Snap been audited? Yes, the Avail Snap has been audited by [SayFer](https://sayfer.io/). ### How do I reach out to the Avail team if I have any questions related to the Avail Snap? We are always happy to help out our users. You can reach out to us on [Discord](https://discord.gg/AvailProject). ### Bridging - [**Bridge b/w Avail & Ethereum**](/docs/da/user-guides/bridge-avail/avail-ethereum) - [**Bridge b/w Avail & Base**](/docs/da/user-guides/bridge-avail/avail-base) - [**Bridge b/w Ethereum & Base**](/docs/da/user-guides/bridge-avail/ethereum-base) ### Using the Explorer > **Note** > > The Avail network has two main explorers that can be used to browse the network: > > 1. [Avail Apps explorer](https://explorer.avail.so/): A dev-focussed explorer with powerful tools to work with the network. > 2. [Subscan explorer](https://avail-turing.subscan.io/): A simpler, and recommended way to explore the network for most users. > > This tutorial will focus on helping advanced users and devs get started with the Avail Apps Explorer. ## Switch networks #### AvailApps Explorer > **Note** > > The Avail Apps explorer currently supports [Avail mainnet](https://mainnet.explorer.availproject.org/) and [Avail Turing testnet](https://turing.explorer.availproject.org/). To switch networks: 1. Click on the `Network name` on the top-left. 2. Depending on the network you are on, click on `live networks -> Avail DA network`, or `test network -> Avail Turing testnet`. 3. Click on `Switch`. #### Subscan Explorer > **Note** > > The Subscan explorer currently supports [Avail mainnet](https://avail.subscan.io/) and [Avail Turing testnet](https://avail-turing.subscan.io/). To switch networks: 1. Click on the drop-down near the top-right. 2. Click on the network you want to switch to. ## Look up the details of a particular transaction > **Note** > > 1. Due to how the network is designed, it is not possible for the `AvailApps` explorer to query a transaction's details using just it's hash directly from a node. > > 2. The `Subscan` explorer however, makes it possible to do so, since it queries from a dedicated indexer > built on top of Avail to support this feature. #### AvailApps Explorer > **Note** > > **Search for a txn using it's `block number`/`block hash` *AND* it's `transaction hash`** 1. Search for the `block number` or `block hash` of the block your transaction was included in. 2. The explorer then fetches all transactions from that specific block. Click on the hash of the transaction you are interested in to get a detailed view. #### Subscan Explorer > **Note** > > **Search for a txn using just it's `transaction hash`** 1. Just paste a`transaction hash` and click the `search` button. 2. The explorer then fetches the transaction details and displays them. ## Create accounts within the explorer #### AvailApps Explorer The `AvailApps` explorer can be used to add or import Avail accounts into the explorer. To go to the page, click on the `Accounts` tab on the top-left, or click [this link](https://explorer.availproject.org/#/accounts). 1. The `accounts` section shows any accounts created straight from the explorer. You don't need any wallet extensions to create or use them. 2. The `extension` section shows any accounts connected to the explorer from wallets like `Polkadot.js`, `Subwallet`, `Talisman`, etc... The following gif shows you how to create an account straight from the explorer: You can do a few things here: 1. Create a new account using a `mnemonic` or by clicking on the `+ Account` button. 2. Import an account via an encrypted JSON file. 3. Connect extension accounts from wallets like `Polkadot.js`, `Subwallet`, `Talisman`, etc... 4. Create a multisig account. We have covered instructions to do so [in our docs here](/docs/da/user-guides/avail-multisig). 5. Create a proxy account. We have covered instructions to do so [in our docs here](/docs/da/user-guides/proxies-on-avail). 6. The `AvailApps` explorer also allows you to use hardware wallets to safely connect cold accounts. We have covered instructions to do so [in our docs here](/docs/da/user-guides/ledger-avail). > Any of these accounts that you connect can be used to sign transactions on the network. Which is something we will cover in the next section. ## Using the explorers to interact with the network #### AvailApps Explorer Wrt interacting with the network, the `AvailApps` explorer can be used to: 1. Query data from the network by calling `Chain State` or `RPC` methods. 2. Send transactions to the network by signing and submitting `Extrinsics`. You can find them within the `Developer` tab. > **Note** > > **WHAT ARE PALLETS?** > Avail organizes its runtime functionality into `pallets`. Each pallet is a collection of calls and extrinsics of a specific functionality. > For example, the `data_availability` pallet contains all the calls and extrinsics related to querying and submitting data to the network, and so on. > Some methods might be grouped into seemingly unrelated pallets for technical reasons, but this largely holds true. > > To look for a particular method within the `AvailApps` explorer, you need to know the pallet it belongs to. ### How to use the explorer to query the network Let us learn how to query the network using the `AvailApps` explorer by querying the balance of an account. 1. Either go to the `Chain State` methods menu from within the `Developer` tab or click [on this link](https://explorer.avail.so/#/chainstate). 2. The balance of an account can be queried by calling the `account(AccountId32)` method from within the `system` pallet. Select the `system` pallet from the dropdown on the left, and the `account(AccountId32)` method from the dropdown on the right. > **Note** > > **THE `include option` TOGGLE** > This toggle allows you to enter params for a method when it is toggled on. > You can also call methods without passing a param by keeping it off. \ > But `system_account` method won't return anything without an `AccountId32` param being passed to it, so we will keep it on. \ > **Hot tip:** Try calling the `dataAvailability_appKeys` method with the `include option` toggle off to see what happens. 3. Either paste the address of an account in the `AccountId32` field or select an explorer-connected account from the dropdown. 4. Leave the `blockhash` field empty (This will query the latest balance of the account), and click on the `+` button near the top-right. 5. And that's it. You just used the `AvailApps` explorer to query the balance of an account on the Avail network. You can query other methods in a similar way. ### How to use the explorer to send transactions to the network You can also use the `AvailApps` explorer to sign custom transactions/extrinsics and submit them to the network. We have covered different examples of doing so in our docs. Here is one of them: [Submit data to a particular `AppID`](#how-to-submit-data-to-my-appid). ### Bonus: How to query chain constants using the explorer 1. The `AvailApps` explorer allows you to query the current values of all of it's runtime constants by going to the constants tab within `Developer -> Chain State`. 2. For example, to query the current value of the `existentialDeposit` of an account on Avail, which is the minimum amount required by an account to exist on the network, you can call the `balances_existentialDeposit` constant. > P.S: The balance displayed is in `attoAVAIL`. 1 `attoAVAIL` = $10^{-18}$ `AVAIL`. 3. You can look up any other constant in a similar way. #### Subscan Explorer The `Subscan` explorer leverages it's dedicated indexer to enable users to browse the network in some neat ways. 1. You can browse network activity more conveniently by using different filters. > **Note** > > * `Blocks`: Browse blocks by number. > * `Extrinsics`: Browse all extrinsics submitted to the network. > * `Transfers`: Browse all extrinsics that involve `AVAIL` token transfers. > * `Data Submission`: Browse all data submissions to the network. 2. The `Staking` section allows you to browse the staking activity on the network. 3. The `Governance` section allows you to browse all governance-related activity on the network, including all past proposals. 4. The `Tools` section supports some useful features: > **Note** > > * `Charts`: Some charts for a visual representation of network activity. > * `Account Format Transform`: Transform an account address into different formats supported by various Substrate-based chains. > * `Price Converter`: Lookup the historical price of `AVAIL` by `block number` or `timestamp`. > * `Runtime`: Browse data related to runtime extrinsics. ## Working with App IDs in the explorer The following sections walk you through querying, creating, and submitting data to App IDs using the AvailApps explorer. ### How to check the next available `appID`? Anyone can create their own `appID` on Avail DA. Let us first check out the next available `appID` on the network. 1. Make sure you're on the `chain state` section of the explorer. You can access it by [simply clicking this link](https://explorer.availproject.org/#/chainstate), or by navigating to it through the `developer` tab near the top right. 2. Within the `dataAvailability` pallet, select the `nextAppId` method. No need to pass any params, just click the `+` button next to the method name. 3. You will be returned the next available `index`/`id` for a new `appID`. ### How to register my own `appID`? 1. Make sure you have one or more Avail DA wallets connected to the explorer. If you don't know how to do so, you can follow our docs on [setting up a new wallet](/docs/da/user-guides/accounts#creating-an-account-on-avail-da). 2. Simply [click this link](https://explorer.availproject.org/#/extrinsics) OR navigate to the `extrinsics` section of the explorer through the `developer` tab. > **Note** > > Please note that the `Developer` tab does not show the `extrinsics` section at all if you don't > have a wallet set up on the explorer or an extension wallet connected to it. > So make sure you have an [Avail DA wallet set up](/docs/da/user-guides/accounts) before moving forward. 3. Select the `dataAvailability` pallet, and the `createApplicationKey` method. 4. Enter a `key` for your `appID`. It can be anything you like, really. 5. This is how it should look like in the end: 6. Click on `Submit Transaction`, and then click on `Sign and Submit` in the box that pops up. > **Note** > > **DO NOT CHANGE THE `appID` FOR THIS TRANSACTION** > > 1. Each and every single transaction on Avail DA has an `appID` associated with it, which is **greater than or equal to** `0`. > 2. A transaction or data submission with the `appID` of `0` is used for **chain-level** operations. > 3. This is what we need to use for creating a new `appID`, since the act of creating a new `appID` has nothing to do with a specific '*app*' on Avail DA. > 4. This field would instead have been a positive integer if we, for example, were submitting data to a specific application on Avail DA. 7. Authorize the transaction through your wallet, and you're done! You've successfully created your own `appID` on Avail DA. 8. You can verify `7` by using the steps covered earlier to query the `appKeys` method :) ### How to submit data to my `appID`? You can submit data to your, or any other `appID` on Avail DA using the explorer by calling the `submitData` extrinsic from within the `dataAvailability` pallet. 1. Make sure you have one or more Avail DA wallets connected to the explorer. If you don't know how to do so, you can follow our docs on [setting up a new wallet](/docs/da/user-guides/accounts#creating-an-account-on-avail-da). 2. Simply [click this link](https://explorer.availproject.org/#/extrinsics) OR navigate to the `extrinsics` section of the explorer through the `developer` tab. 3. Select the `dataAvailability` pallet, and the `submitData` method. 4. Enter a random `data` string that you want to submit to your `appID`, and then click on `Submit Transaction`. 5. Fill in the `AppID` that you want to submit the data to. Click on `Sign and Submit` to authorize the transaction through your wallet. 6. Wait for the transaction to be included in a block and then open the detailed view of the block. 7. Click on your specific transaction to see it's details. This is what it should look like: ## Wrapping up We will update this page with more examples and information as we go along. Feel free to join [our Discord](https://discord.gg/AvailProject) and suggest any additions that you would like to see here. ### Identity ## Introduction Avail allows you to set canonical on-chain identities for your accounts via the `identity_setIdentity` extrinsic. \ The AvailApps explorer provides a convenient UI to set an identity for your account, which is what we will be doing in the next section.
Identities vs Sub-Identities 1. Each account on Avail can create a main identity and up to 100 sub-identities. 2. Each of these sub-identities are linked to the main account. 3. A possible way of using this feature could be to create a main identity for your team, and then create sub-identities for each of your team members. 4. A deposit of `2 AVAIL` is required per sub-identity.
> **Note** > > 1. Users need to lock a small account of `AVAIL` to set an identity, which is refunded if and when the identity is cleared. > 2. The bond amount for registering an on-chain identity is currently **100 AVAIL**. > 3. The bond amount for registering each sub-identity is **2 AVAIL**. > 4. The maximum number of sub-identities per identity is **100**. ## Set Your On-Chain Identity > **Note** > > **PREREQUISITES** > The only prerequisite is that you have access to one or more Avail DA accounts. > Refer to our docs on [setting up an Avail wallet](/docs/da/user-guides/accounts) for more details if needed ### Navigate to the accounts page on the Avail Apps Explorer Go to the [accounts page of the Avail apps explorer](https://explorer.availproject.org/#/accounts). Select the account whose identity you want to set and click on `Set on-chain identity`. ### Fill out the fields that you want to set Fill out at least 1 or at most all of the available fields. All the fields are optional as long as any one of them are filled. ### Submit the transaction Click on `Set Identity`. Make sure the `appID` is `0`, and click on `Sign and Submit`. > The account will now have a registered on-chain identity which you can clear to recover the bonded AVAIL tokens. ### Ledger Avail DA is a modular blockchain built for the next generation of rollups by being an effective and efficient solution for the [data availability problem](https://blog.availproject.org/data-availability-what-is-it/). The AVAIL token is the native token of the Avail DA, used to perform basic transactions, as well as to submit data. It therefore becomes crucial to store your AVAIL tokens securely, especially for wallets with large amounts of them. This guide will take you through verifying, rejecting, and approving a transaction on Avail DA using a Ledger wallet. ## Prerequisites 1. A ledger device. Refer to [ledger's official website](https://www.ledger.com/) for the same. 2. The Avail app for ledger should be installed on your ledger device. You can do so by downloading the [ledger live app](https://www.ledger.com/ledger-live) on your computer or mobile and use it to install the Avail app on your ledger. > **Warning** > > If you're using a new ledger device, it is highly recommended to ensure it's firmware is up to date before anything else. > You can update it's firmware using the ledger live app. ## Set up your Ledger from scratch ### Video guide If Youtube is more your style, you can watch the video guide below: ### Install the Avail app on your ledger device 1. Open the Ledger live app and naviagte to the 'My Ledger' tab from the sidebar. 2. Search for the `Avail` app inside the app catalog, and install it on your device. Ledger live app 3. Once installed, this is what your ledger device's homepage should look like: Ledger device homepage ### Open the Avail app on your ledger device > **Note** > > Please note that you will need to have the Avail app open on your ledger device to interact with Avail DA in any capacity. This is what your ledger device should display when the Avail app is opened: Ledger device with Avail app open ### Derive an Avail DA account online using your ledger device 1. Go to the [settings tab of the Avail apps explorer](https://explorer.availproject.org/#/settings). 2. Click on `manage hardware connections` and select `Attach Ledger via WebUSB`, then save the changes. enable ledger services in availapps explorer 3. Go to the [accounts tab of the Avail apps explorer](https://explorer.availproject.org/#/accounts). 4. Click on `From Ledger`. Avail explorer accounts tab 5. A form will pop up. Give your derived account a random name. 6. Choose a top-level and a second-level derivation for your account. We'll be going with `0` and `0` respectively. Avail explorer ledger derivation form > **Note** > > Any account address generated from your ledger will be a unique combination of your ledger-device's > seed phrase, the top-level derivation, and the second-level derivation. > This means if you re-connect to the avail apps explorer with the same ledger device in the future (that has not been reset), and use > the same top-level and second-level derivations, you will get the same account address. 7. This is what the accounts tab should look like after you've derived a hardware account: Avail explorer accounts tab with hardware account 8. Make sure to send some AVAIL to this account to interact with Avail DA. ### Sign a transaction on Avail DA using your ledger device 1. Click on the `send` button alongside your ledger wallet. 2. Enter a recipient's address and an amount to send. 3. Click on `Make Transfer`. 4. Make sure the app id is `0` if you're performing a simple transaction. > **Note** > > Please note that non-zero app ids are used to submit data to Avail DA. > For all top-level/simple transactions, the correct app id is `0`. 5. Click on `Sign and Submit`. 6. At this point the explorer UI will wait for a signing/rejection of the transaction from your ledger device. 7. You can verify important details of the transaction from your ledger device, including the destination address and the amount of AVAIL being transferred. This is what it should look like: Ledger device transaction details 8. Once you are done verifying, `Approve` or `Reject` the transaction using the buttons on your ledger device. 9. Once the transaction has been finalised, you will see a success message on the explorer UI: Transaction success message ### Support If you face any issues while using your ledger device with Avail DA, please feel free to reach out to us on our [Telegram](https://t.me/AvailCommunity) or [Discord](https://discord.gg/AvailProject). ## Add your Ledger account to an extension wallet If you have set up your ledger device and want to use it through a dedicated Avail wallet, this section is for you. We have included instructions for connecting a ledger account with Subwallet & Talisman, but the process is similar for other wallets. > **Note** > > If you are looking for instructions on getting started with an Avail wallet, you can refer to our [accounts guide](/docs/da/user-guides/accounts/#creating-an-account-on-avail-da). #### Subwallet ### Prerequisites Make sure your ledger device is unlocked and the Avail app is open. ### Click near the top to expand the list of accounts ### Click on `Attach account` ### Select the `Connect a ledger device` option ### Search for the `Avail` app and click on `Connect` ### You can now select as many or as few of your ledger accounts to your Subwallet extension wallet ### Click on `Connect Ledger device` to finally import your selected accounts #### Talisman ### Prerequisites Make sure your ledger device is unlocked and the Avail app is open. ### CLick on the `+` sign next to the accounts tab ### Click on the `Connect` tab and then on `Connect Ledger` ### Select the `Polkadot` option ### Search for the `Avail` app and click on `Connect` > **Note** > > **MAKE SURE YOUR LEDGER DEVICE IS OPEN THROUGHOUT THE PROCESS** ### You can now select as many or as few of your ledger accounts to your Talisman extension wallet ### Click on `Continue` to finally import your selected accounts ### Proxies ## Introduction A *'proxy'* of an account on Avail DA is simply another account on the network that has the power to sign transactions on behalf of the original account, also known as the *'proxied'* account. We can also configure the proxy to only have permission to sign a subset of all possible transactions on behalf of the proxied account. We will learn more about this later. > **Note** > > **MAKE SURE YOU'RE COMFORTABLE WITH THE LINGO** > > * *'Proxy'* - A proxy is an account that has the power to sign transactions on behalf of the proxied account. > * *'Proxied'* - Refers to the original account that the proxies are signing for. > * *'Any proxy'* - An account that has the power to sign any type of transaction on behalf of the proxied account. > You can have many different types of proxies on Avail network. Refer to [this section in our docs](/docs/da/user-guides/proxies-on-avail/avail-proxy#proxy-types) for more information. ## 'Proxy' vs 'Pure proxy' You can create two types of proxies on Avail DA: Proxy vs pure proxy ### Proxy accounts When creating a proxy for an account you own, you choose the exact address of the proxy, which may or may not be an address that you control. You can do this using the `proxy.addProxy` extrinsic. The Avail Apps explorer provides a convenient UI abstraction for this, instructions for which can be found here: - [**Proxy accounts**](/docs/da/user-guides/proxies-on-avail/avail-proxy) > 👉 The key principle to note here that is that you can create a proxy account that is not under your control.
For Example You might have an account with a significant amount of funds that you want to stake on the network without taking on the responsibility of managing the staking operation itself. You may, in this scenario, choose to add a friend's account as a proxy to your original account, but with the stipulation that this proxy can only sign staking-related operations on your behalf. You therefore have a situation where a second person has the power to stake funds on your behalf, but without the ability to outright transfer your tokens away.
> **Warning** > > 1. The example above was a hypothetical scenario. Please take care while delegating responsibilities to proxies that you do not control. > 2. You can always revoke a specific proxy's permissions using the `proxy.removeProxy` extrinsic. ### Pure proxy accounts When creating a pure proxy for an account you own, you do not get to choose the address of the proxy. Therein lies the key difference between a proxy and a pure proxy. While you get a deterministic address in the first case, the proxy address is randomly assigned in the second. You can create a pure proxy using the `proxy.createPure` extrinsic. The instructions for this can be found here: - [**Pure proxy accounts**](/docs/da/user-guides/proxies-on-avail/avail-pure-proxy)
Why would you want a pure proxy? You will see this more clearly in the [dedicated guide for setting up pure proxies](/docs/da/user-guides/proxies-on-avail/avail-pure-proxy), but the short answer is that using a pure proxy setup allows you to conveniently rotate the any proxy behind the pure proxy without having to move funds out of the pure proxy. This is especially useful when the pure proxy is being used to hold funds on behalf of a committee that needs to vote on proposals using a multisig, which acts as the any proxy for the pure proxy. For example: 1. Consider that a pure proxy account is being used to stake `AVAIL` on the network on behalf of a committee of 3 people. The committee votes on proposals using a multisig, which acts as the any proxy for the pure proxy. 2. If one of the committee members needs to be replaced, a fresh multisig will need to be setup to accommodate the new member. 3. With a pure proxy setup, the old multisig can simply be rotated out in favour of the new multisig without having to unstake or move funds out of the pure proxy. 4. Any other way of implementing this would require an unstaking of funds followed by a migration into a new account.
> **Note** > > Since nobody actually owns the private key of a pure proxy, it cannot be compromised via a private key leak. ### Staking & Governance Stake AVAIL tokens and participate in governance. Start with [The AVAIL Token](/docs/da/user-guides/staking-governance/overview) to understand tokenomics, then explore staking and governance. - [**The AVAIL Token**](/docs/da/user-guides/staking-governance/overview) — Token supply, distribution, and utility on the Avail network. - [**Stake on Avail**](/docs/da/user-guides/staking-governance/stake-on-avail) — Nominate validators and earn staking rewards. - [**Avail Governance V1**](/docs/da/user-guides/staking-governance/governance-on-avail) — Propose and vote on network changes through on-chain governance. ### Get current Avail head ## Request * `Path`: `/avl/head` * `Method type`: `GET` ## Example Request #### CURL ```bash filename="CURL" curl https://turing-bridge-api.avail.so/avl/head ``` ## Example response ```json filename="Example JSON response" { "data":{ "end":512738, "start":488581 } } ``` ### Get current Ethereum head ## Request * `Path`: `/eth/head` * `Method type`: `GET` ## Example Request #### CURL ```bash filename="CURL" curl https://turing-bridge-api.avail.so/eth/head ``` ## Example response ```json filename="Example JSON response" { "slot":4454752, "timestamp":1709191840, "timestampDiff":1716 } ``` ### Get bridge deployment details ## Request * `Path`: `/info` * `Method type`: `GET` ## Example Request #### CURL ```bash filename="CURL" curl https://turing-bridge-api.avail.so/info ``` ## Example response ```json filename="Example JSON response" { "availChainName": "hex", "bridgeContractAddress": "0x1369A4C9391cF90D393b40fAeAD521b0F7019dc5", "vectorXChainId": "11155111", "vectorXContractAddress": "0x570f6a1936386a4e060C2Daebbd0b6f5C091e13f" } ``` ### Check liveness of server ## Request * `Path`: `/` * `Method type`: `GET` ## Example Request #### CURL ```bash filename="CURL" curl https://turing-bridge-api.avail.so/ ``` ## Example response ```json filename="Example JSON response" {"name":"Avail Bridge API"} ``` ### Get Merkle proof for a particular extrinsic ## Request * `Path`: `/eth/proof/:blockhash?index=` * `Method type`: `GET` ## Example Request #### CURL ```bash filename="CURL" curl "https://turing-bridge-api.avail.so/eth/proof/0x5bc7bd3a4793132007d6d0d9c55dc2ded2fe721a49bd771c1d290e6a3c6ec237?index=5" ``` ## Example response ```json filename="Example JSON response" { "blobRoot": "0x511030804f9768c9d5c4826cdc7eba25ba0fd8e73ea32467e5fad547397620f8", "blockHash": "0x5bc7bd3a4793132007d6d0d9c55dc2ded2fe721a49bd771c1d290e6a3c6ec237", "bridgeRoot": "0xf6c807bc73a637957a61d620bd5e4ef8c7dd234e5fc96dfb6d6041bbe2947782", "dataRoot": "0x2179e18ee112b080794b40f2239d77041c715ad7392d9fce054b7c10eacd4ebc", "dataRootCommitment": "0x41cfe14b2e229cc5b4ee0cb7c3c909e1f78ae9e32f986e7496bfd4e007e06519", "dataRootIndex": 48, "dataRootProof": [ "0x0395f21560a9ccc1f2aa972601250256fbdb20fd936e1723397ff8d5e4f07b5d", "0x1e91eb5ce2802373a583ce83898e8b4c1bb648e3c76bad87820a197b73b6d23b", "0xd49b33b5754aa6c9549e9677e4c646bd4e7d500a2ab9761cffff5363f4608ac7", "0x575858cb3bb948af2d8c4582310f951eb798281f71e913e044c6c415031f58a3", "0x353fe475ab9b0e00c3bfae8598fef61ac2921a7928b21ad45b6594c023611156", "0x4cb574d05c6606d2509ec6849e0cb53d04c5eead1cdbed4704018da938df5460", "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c" ], "leaf": "0xe17de7631392427460102691ba8a22adf5fb410548e50d6c636bf1f96840c3c3", "leafIndex": 0, "leafProof": [ "0x00017cadd87ec12039f98d646afaa33ed843056ad12f5e971cc81be15d00c26f", "0xd046caabde74922f9d69e9fd33de6d3b9ee0f5c536183c4f4259f078afda538a" ], "message": { "destinationDomain": 2, "from": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "id": 256491151949829, "message": { "fungibleToken": { "amount": 5000000000000000, "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" } }, "originDomain": 1, "to": "0x0000000000000000000000000000000000000000000000000000000000000000" }, "rangeHash": "0x21c402a3ccf8df26cb720c6d2fb409f04c809adef7a9a852e463cca83588f4fb" } ``` ### Get storage proof for a block ## Request * `Path`: `/avl/proof/:block_hash/:messageId` * `Method type`: `GET` ## Example Request #### CURL ```bash filename="CURL" curl "https://turing-bridge-api.avail.so/avl/proof/0x7963d8403d137cb5560e2436df07c233d18030b5f3f0c61b85083e2a8f2b5e55/1" ``` ## Example response ```json filename="Example JSON response" { "accountProof": [ "0xf90211a04ea3386c3564d92c70c842f4fe40a382ab0c0915bd52f1cfdf515e7df40f6365a05fd188dd610941144f5367487b343528f30b6fe1713e14c489a925d31b76de8ea081a4596748d2119583d96af1f6459bfc4d4cf48e5cf9f4171bb0f15b54bfc705a0934bf30f9e4643c1e8cabd31b65867d5dce6702ff922d5d5f88edd77c16eddf8a020c236a887760702595f069baa5c20a5d7f7ff56e99e4f2291e6c383ec2f1376a0a4c5d6569cf6acb8b7b744bdb847ee84c7a250a05858f21c4b71e892e0f6368ca0431a25d2f4d04d92b7f663f91b65029bd2a443fdcd71d6a5d1cd2bad5f937da5a09d5da24c3c97ebd7ed4897206e30464414bdaf91fb633ef6e5aa61ec4573b829a0e1850f0a51e6f8fb4e7b7d0a592a478e4fd4f55132faad2e05c774f2c5bf3722a0e437d19bee3cdd31e6a54da59dd1730d20ad59b1e816ba304b0f8cf89fa62697a07c9058190b5603de7af44f45d2654832a5e5186db18b28514101f5df81287a27a08637a03272d24e7d380f3d68a38525d0348cce5fe90ae32f2b51149badd96f75a0d45f94f513a8918bafb074ac20f951e6ddd59cfa414550ea7af155ea7530e386a03dc457251a135a4002731a17ee72e722897a64509dd108eeb729bb1d9a84bf3ca0e1834ab71a27a983540fee14db56a40c26e3936db6b76d950a117acd5d2a03fea053388d24ffe072f62c6ed5dc8d8e286e167648a5bed4f9a1445df2b2581a589880", "0xf90211a05f1dfe6f285811ddc2b5c1b2e0b4c9715586274627a60885abf66fe60f58f39ea098709a8cac54a765fa8b09b12849171bc2aadece08d4d21e2631efb92e422a72a09456842fb2f41eeaad70f98549983ec28ac5cc97b2bacd325a341bf8fecbd3fda012f6579824d8706f219fab4e6209270b3c5a7f9b9b10434422173bee004ebf87a0cad660f5066719c1e57fa895b385aedb678d89843f93fa9d284137cce585d912a08aee33972b41bd2c81bb805877f91b5c720c518551071c8c7b7b5035fc855dcaa0fe78af4efca09613a5b166012ad59ce6450d8f612d872010b8cb2cfce5171e01a0ed34274b556d95bc83b368a313d81e2418c84435e094626f568294de2c6adda3a0c4a8516496de7bd739485f7f0ea764e5f1e64f18ea24d5c2662df9321ad476b0a0c3ac05b241ad4ce2e59c05d280a56cdcaa38b8d974d0086a517ea0e71f47dbbba0c786b94bc71965e950e2cddbc6dc3d20b9527f14ac6720dffd93531f58cbb2caa0db4936424a52afb5f811937e21c36dbfc115f36167f57ea0f0770ba5b2b01509a08bfc560bf436ebfd1b9b2a16b38c37fdef7b27b5c5facf3d8487034100e04da3a0d19c58734f31adc98c08131a3f441d4945c63a569d381265517fb270d149fcd9a0a49a515f1d226b9a55079dd09128e8d068ce4473fc2afc7ce83ca73b4a4aeca8a039f4a70c5da7a6f9a75ccfbfa4e4660f367d83ed133633a09d8d85f3b81619b080", "0xf90211a013013c8d88c90029dae1eb17e9fde9d31aa12a845f977d5b05edfbb836490ed1a08313217b9700aa20e3f2bca060da9c6986794e32e39ee8378c5fc090ea3900c4a0bb6f74f7517cc6d53e1ac28cda4b7492460eac8ad25dae2e6f5dd83054975f5aa06591f5961ce401397d1b7ca8ace8c514f0711029a4804afc5dff746535f4b310a0acb9ff577f6e255b1739bdca46b3fca567678334cef7a7c3459110d398117ca0a0ca52f676d720f2148ea17a8949d8456043eca88e500c0455de24bd5f97c4574ba043f8dbbd691453a0601664d5a35b89b7980c679924f93427d446ccb4b8f54bfba0429ee0cf4db61c968b343ade1502260068beaa87dc31e673c3abeaad60dbe7a5a03e27446763b24c289f918b1710dd069019fb95cd822997fb6fbc1db75ac8b0eca0fdf20b9898a99a2378bb653195060908595370eb56d905306ca1d1260d5c4120a0c63d1fb8a5be22724ea48117eab3b87f9a2ff76c6dec7f3568ddc16098f31b68a0e527b82ba67b4d9299c0e11f48362894ff615bf39e36ccde2d4e13b636262833a008b21c1e3dc4c5938833ed344842aff4a75297019736e1b66820a959d3092561a02bcb48ab6bf1b0b426008ab0919010b847473a3710806632bed77f05d10b2f5ca09b61c79db573dcc92d61a101051e2cffc43389cbffb39cba671fd5a706c26cd1a030051e73e7a062b2812459e8cd4c2db94c408f2dc706fc16ed632cda8707f3bd80", "0xf90211a007df9be996660f9f91495c59b998832068088ae9034c5b04639694168b9571e6a0aa1dc52398e74cf48729ec879a6ee91c2e73cc73c076f953dda4dfe580ff05e3a0afc1d0a6d1d8723d5c16d5b25673eb3f4d05ef1466612ee9182781bbe987611ea038064f5d9c62106631b05c606352db759e3b535cdafeafb16638c9515731a7cba06800f0958bb61b89dd4bb02eb3da4bf6c14ad00b4a48a66019b0e6d15cc84ee1a08c149b7166f15e51a524ee32ea212f60d6df6a800e01d4fa22ffede5a39ee9e5a093922185d4bdbe12d5e5c62194739038e89b01d67f476acc8865817ac7ed9008a016d39ae51fad6e0f060d8653d173460ed52a823010a29db6edbc042b21e78fbca0f2c153d9c2c2b50644bc8098925dbb3ed618fa7e82ebb94e40965b2c977b6811a01f01669c56000db9ac524e334dace75e9f082db5c95ed9075caacc99165abc76a04ced0f74f50c438075f4d18fe1a0bbafa324e4a5a0d5fb7865acb35c72533e4ba0c8053b16343a4f4dd43ab76abb1cac2f8e791fdb3fa9121014cf7a42151860d3a06961b3a4f6ca879e0377f734d66f930af3258e1492be0c693d395c84a311a644a0a38ea23af3ce3d1d5b485a5c264f9cffaabe184e362466de6bf6e634062f5548a062843d42cff1c276a0e11cc1c6921151b7e84b8de41a2834c0beac97f6a07de3a0609f8c69b1fc2754e2d08946285d80a5a319647acef900dd97a62d21258a035880", "0xf90211a0aec1c4685e2c3b64c256d10b3135ef48b013524839f8373dbd0bc0eac8d7ba1fa05ab97dd3b415869a2674d9dd1744abfb45de8dffc2c302b05c1336d40c80cf14a07ad83ef3d645503b9afcf48de32fb677beef8b637aa120e6624acea518eb5b3fa030775e5e8230f409c292e2d4033a7530f83656cb67148acc599d37f782f8ef8ba013f3d308779aeb8958a612b37a07807a1783b0f99e1e5f76303fb7c3c44d622ca06e7b7e9dcfc4c24c702aef326848015731a4e20f0d8a02a401197e99c62ca1d7a0ae60461c17040fd1475fceac5e5f5528d2b972b084b4d5413f8cfb41f1ac7075a029a319fc16340bb5889952869c0184a1fc1d0427aa488dd597909671c9b41b6ca03abb30bb5daf1a503a65f2e7979f61ed288f163937406758e2a44ed7a751d216a04e9cfefe88b368b66e1da951909d6e6ce639845c19690778f6e316c9dc902d52a0c7eb14d0cf6465626d7834f200810b009aeb7b13f384c096ebe3ec503b75f4faa0ad3c0d202e74be0f188316e4e466ae7fca89b6a20994b22747b2f95febf5a449a0692d63a3756a510f8467f7da09e97da406265b4201fa4fe3577cbb887045cd6ea093b71eb86d53ddf8d13df0e7c446867dbacf096455045a2bd9690c56a443b4c3a0e712c0b14d1130db6db7edd7a93af2fc1a06d2e5793c4e54dcacca98b4cc6997a0bcc85c28e9f209b9b419e66f87bce37fbb42ba8416880935275c377d2fcebcc180", "0xf90191a0deb916373640a76bb6056aa37e9d548908c92fb5d3ea1fc69a1c99ddeb40eb24a029b4cdce0d4f7eed71cf6f6d21f4d27ef510b3e36c7c67587e84a08b8b288de380a0cd92c24f26cec2802437f2f8e56cdd35e47ed3edc4c806540740f5bf83f1c5ffa0aadf083c80930dee9f09d295708b24f31d2f41f50e1442e32ecbf03eb5b4a707a0f5335f3280d3be255686e95e46a353a1562a8008919a0051a46fb3fcce7c53caa07f9373bba9b4111e6d4ef57fecd16526497cdeaceccdb26ae09c526b834c83c3a0d000e75b89a65aedb850451d369e3ac5bf4d7ff0d71ec5e837417c0eaf074135a0a994cad72a8a641c62979d6f94ea0087a14770876869de76ff0aba4c51b7cfc480a094b7d0ec3e0de0f4135fed0b225c1a5f09fd8660e37fa7ee3d47cdf774fe4940a06e2c53738e77dd7b3c06aada2fcd6035a8435f8edbd40e0e9856439024502a2fa000e7bef9cf8c6301c9d0aba5e61136a898292f1cbde8861987d0999358f5505f80a0c232ad4a9e338ea79c8f86fc6a83952f212b4477a031a3c24d98d5aac8ef1fac8080", "0xf87180808080a038eace52a35a1cb3ba4dfc5a7dd4fd884d999c017dd48546779e9b1ceee867f3a07564257a73fdfa4e290ad21fe914294174996ac87095b5730370371f5ea133e980808080a0d51dbe737bf6d8c5b89bcf7724074067d2a4986c4180a5016a8bebfbc92f56e1808080808080", "0xf8669d38b7b6c4749ee47ec3483ea3325831ccd2fbcbbbcf7cb559ed13d35a14b846f8440280a0927826564770fb917bb1bc72e196fcf2fe2601c838c744106d1691a9da45b795a0fc50d62823735da871a4b45630e8f4a5aef99c18855869762b05d4f7fac4a859" ], "storageProof": [ "0xf90211a02b61c0a3f1012b0c3fe640d90daf8f756f30665e9763d97c2809e683f57418bca0ca985e3b14af8741416d7c735fcc856c510138e8a82edd8506e49d8cac71258ca0bfebf2d2da505708433ec9e6d7d6f5f5706b502435ad98b8429f04f497f1e79ca0481bcb4d57a33e6fdd2d824b3f0bea708c76f437b114d043da26a9b019220552a01e5139fa355fc9ab10b4901bb0a1aee4b97b21441f3a6c2ecccadd2009b6e34fa05806452c1672d430087e3aac3e49901fe6788e8d5e2db17140ed49d3e4a6e262a00bc15c11195738ae6967054b12acc80948f99d852b3a05b2572407c67e98dfaca028fa67ddfd82c094d593d0001f099cff4f5bdad51cf0d77f4e5d15243c23701fa06ddefc9d483203b04420fc19c1de59664c839a726edb7cd6d519f63444293567a0fa38292ed34577ba490dfb1335d9ee2871bf64a498d8af13eb665516bc122fc8a03b6f3c05d6c9151aa3f552d3088d12e80ab70d78ef046ddf4d311dc35fd89699a02bbf18d484d22ce32d8efb9ad5236ca770f34ca46093a062c9fd0c00fce179b1a093e4702951798f5331327b8a6a613307e12edc789dc1ddb21ba4ef185122cedda091b0434eedf92e47d68213d40c2ead10fb94f7ce34845d9b85ddc255a5586f98a0b6a8a018fe45d5a78c237915cdc4db38a151c2078e9fd72ed53481072e816366a0c4a7126e02988de7caae8abdd299cf6fbde0eb2adc9be75ded86e8ea8388dead80", "0xf90151a0401fa10b5959532f16179be0bd2506e7f849495298c2de8fd5b8c4d63b1f2c1ca01dcc18ed03ed3183fe26600b23afedbebdd947d6b5019cc010ea359e0234afe0a050030a57a0878bb51bbd0c62d3ba0c2b782ebc5d6ec012a7a1bd0f20917558b6a0db69566205faf59c73db049a04d81f63db7d2dbafbe66ed91557e511ed0938d780a0e6114e00cb6c2aa9cf632cb93e5ccad1b4c9af79c769950743a647fe829c602ca0bcb35466c5b4c32c509da47141cb7b9c3dddff0ebcd0ea050bad4d398e2fb25f808080a054876fae9e71b3585d4e83ee48c65b366f6f13a3c1b9e2749918145eabd1c46da004531fc338c340e676badc1a99cad6ece2da3d08945f806cb7063bf3343d35f48080a0c68fcd91600b226b6c847f28d2f6ca3f60c55b1009b26e59f4d1087bb5d6fcc0a06c5aec8aa331b1f04b26a06cb64c5a6d63616d717f236d31106751bbea0d666880", "0xf871a08eccb5e838d7d0699e06d85c472bb097d8012c44d790e5d15c5b8465c7abb88180a02581c4c4535083ecd9ea1a314216bbe948f27bccb2e997c7796a9eec8f4c3df0a0c453ceda114a9775f135a7a2687f75e753c6f814789528fb73bb8cb5dec7eac680808080808080808080808080", "0xf8429f31265685397ec9fa17535b5603e86e2b01a583b71373e1b2cbfac2a5bff58fa1a0eb70a047920b4aa1f3a418b52e455694d4e1a2362fd7fbcf16fe53d798311beb" ] } ``` ### Bridge a message from origin to destination chain * On-chain name of extrinsic: `vector_sendMessage` to send a message from Avail to Ethereum. * On-chain name of extrinsic: `vector_execute` to execute a message receieved from Ethereum on Avail. ## Send an arbitrary message from Avail DA to Ethereum #### avail-rust Let us first look at how an arbitrary message is being sent using the `vector_sendMessage` extrinsic below. ```rust let da_call = avail::tx() .vector() .send_message(message, recipient, domain); let params = AvailExtrinsicParamsBuilder::new().build(); let maybe_tx_progress = sdk .api .tx() .sign_and_submit_then_watch(&da_call, &account, params) .await; ``` ## Full Example ### Sending arbitrary message from Avail to Ethereum. Initialize the `avail-rust` SDK. ```rust use alloy_network::EthereumWallet; use alloy_provider::ProviderBuilder; use anyhow::Result; use avail_bridge_tools::{address_to_h256, AvailBridgeContract, BridgeApiMerkleProof, Config}; use avail_rust::avail::runtime_types::bounded_collections::bounded_vec::BoundedVec; use avail_rust::avail::vector::calls::types::send_message::Message; use avail_rust::{avail, AvailExtrinsicParamsBuilder, Keypair, SecretUri, WaitFor, SDK}; use reqwest::Url; use serde::{Deserialize, Serialize}; use std::fs; use std::str::FromStr; use std::time::Duration; #[tokio::main] async fn main() -> Result<()> { let content = fs::read_to_string("./config.toml").expect("Read config.toml"); let config = toml::from_str::(&content).expect("Parse config.toml"); println!("Using config:\n{:#?}", config); let sdk = SDK::new(config.avail_rpc_url.as_str()) .await .expect("Initializing SDK"); let secret_uri = SecretUri::from_str(config.avail_mnemonic.as_str()).expect("Valid secret URI"); let account = Keypair::from_uri(&secret_uri).expect("Valid secret URI"); } ``` Now we set our `domain` (similar to `chainID` in EVM chains). We also set the `recipient` contract address, in this case it will be the VectorX Bridge contract address. ```rust // Ethereum domain let domain = 2u32; // Recipient contract address on the Ethereum network let recipient = address_to_h256(config.receive_message_contract_address.parse()?); ``` After we have all this ready, we just need to define our message and send it using the `vector_sendMessage` extrinsic which is defined as `vector().sendMessage(message, recipient, domain)` ```rust let data = BoundedVec(config.message_data.as_bytes().to_vec()); // Arbitrary message to send let message = Message::ArbitraryMessage(data); let da_call = avail::tx() .vector() .send_message(message, recipient, domain); let params = AvailExtrinsicParamsBuilder::new().build(); let maybe_tx_progress = sdk .api .tx() .sign_and_submit_then_watch(&da_call, &account, params) .await; ``` Finally we wait for the transaction to be included in Avail's block and do some transaction handling. ```rust let transaction = sdk .util .progress_transaction(maybe_tx_progress, WaitFor::BlockFinalization) .await; let tx_in_block = match transaction { Ok(tx_in_block) => tx_in_block, Err(message) => { panic!("Error: {}", message); } }; println!("Finalized block hash: {:?}", tx_in_block.block_hash()); let events = tx_in_block .wait_for_success() .await .expect("Waiting for success"); println!("Transaction result: {:?}", events); let block_hash = tx_in_block.block_hash(); let extrinsic_index = events.extrinsic_index(); let block = sdk .rpc .chain .get_block(None) .await .expect("Get block by hash"); ``` ### Retrieving data on Ethereum Once we have sent the arbitrary message, we can interact with the Bridge API to determine if it has been sent to Ethereum. 1. Wait and check if the block range in which our message is sent has been received on Ethereum. ```rust let block_num = block.block.header.number; loop { let avail_head_info: AvailHeadInfo = reqwest::get(format!("{}/avl/head", config.bridge_api_url)) .await .unwrap() .json() .await?; println!("New range: {avail_head_info:?}"); if (avail_head_info.data.start..=avail_head_info.data.end).contains(&(block_num as u64)) { println!("Stored avail head is in range!"); break; } tokio::time::sleep(Duration::from_secs(60)).await; } ``` 2. Get the proof from the VectorX Bridge API. ```rust let url: String = format!( "{}/eth/proof/{:?}?index={}", config.bridge_api_url, block_hash, extrinsic_index ); println!("Proof url: {url}"); let proof: BridgeApiMerkleProof = reqwest::get(url).await.unwrap().json().await.unwrap(); println!("Proof: {proof:?}"); let signer = config .ethereum_mnemonic .parse::()?; ``` 3. Interact with the VectorX Bridge contract to retrieve the message ```rust let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(EthereumWallet::from(signer)) .on_http(Url::parse(config.ethereum_url.as_str())?); let contract_address = config.contract_address.parse()?; let contract = AvailBridgeContract::new(contract_address, &provider); let call = contract.receiveMessage(proof.clone().try_into().unwrap(), proof.into()); let pending_tx = call.send().await?; let res = pending_tx.watch().await?; println!("Result: {res:?}"); Ok(()) ``` *** image: "/img/docs-link-preview\.png" * Bringing it all together, we have the following. Inside `src/main.rs`, paste the following code: ```rust use alloy_network::EthereumWallet; use alloy_provider::ProviderBuilder; use anyhow::Result; use avail_bridge_tools::{address_to_h256, AvailBridgeContract, BridgeApiMerkleProof, Config}; use avail_rust::avail::runtime_types::bounded_collections::bounded_vec::BoundedVec; use avail_rust::avail::vector::calls::types::send_message::Message; use avail_rust::{avail, AvailExtrinsicParamsBuilder, Keypair, SecretUri, WaitFor, SDK}; use reqwest::Url; use serde::{Deserialize, Serialize}; use std::fs; use std::str::FromStr; use std::time::Duration; #[tokio::main] async fn main() -> Result<()> { let content = fs::read_to_string("./config.toml").expect("Read config.toml"); let config = toml::from_str::(&content).expect("Parse config.toml"); println!("Using config:\n{:#?}", config); let sdk = SDK::new(config.avail_rpc_url.as_str()) .await .expect("Initializing SDK"); let secret_uri = SecretUri::from_str(config.avail_mnemonic.as_str()).expect("Valid secret URI"); let account = Keypair::from_uri(&secret_uri).expect("Valid secret URI"); // Ethereum domain let domain = 2u32; // Recipient contract address on the Ethereum network let recipient = address_to_h256(config.receive_message_contract_address.parse()?); let data = BoundedVec(config.message_data.as_bytes().to_vec()); // Arbitrary message to send let message = Message::ArbitraryMessage(data); let da_call = avail::tx() .vector() .send_message(message, recipient, domain); let params = AvailExtrinsicParamsBuilder::new().build(); let maybe_tx_progress = sdk .api .tx() .sign_and_submit_then_watch(&da_call, &account, params) .await; let transaction = sdk .util .progress_transaction(maybe_tx_progress, WaitFor::BlockFinalization) .await; let tx_in_block = match transaction { Ok(tx_in_block) => tx_in_block, Err(message) => { panic!("Error: {}", message); } }; println!("Finalized block hash: {:?}", tx_in_block.block_hash()); let events = tx_in_block .wait_for_success() .await .expect("Waiting for success"); println!("Transaction result: {:?}", events); let block_hash = tx_in_block.block_hash(); let extrinsic_index = events.extrinsic_index(); let block = sdk .rpc .chain .get_block(None) .await .expect("Get block by hash"); let block_num = block.block.header.number; loop { let avail_head_info: AvailHeadInfo = reqwest::get(format!("{}/avl/head", config.bridge_api_url)) .await .unwrap() .json() .await?; println!("New range: {avail_head_info:?}"); if (avail_head_info.data.start..=avail_head_info.data.end).contains(&(block_num as u64)) { println!("Stored avail head is in range!"); break; } tokio::time::sleep(Duration::from_secs(60)).await; } let url: String = format!( "{}/eth/proof/{:?}?index={}", config.bridge_api_url, block_hash, extrinsic_index ); println!("Proof url: {url}"); let proof: BridgeApiMerkleProof = reqwest::get(url).await.unwrap().json().await.unwrap(); println!("Proof: {proof:?}"); let signer = config .ethereum_mnemonic .parse::()?; let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(EthereumWallet::from(signer)) .on_http(Url::parse(config.ethereum_url.as_str())?); let contract_address = config.contract_address.parse()?; let contract = AvailBridgeContract::new(contract_address, &provider); let call = contract.receiveMessage(proof.clone().try_into().unwrap(), proof.into()); let pending_tx = call.send().await?; let res = pending_tx.watch().await?; println!("Result: {res:?}"); Ok(()) } #[derive(Serialize, Deserialize, Clone, Debug, Default)] struct AvailHeadInfo { data: AvailHeadData, } #[derive(Serialize, Deserialize, Clone, Debug, Default)] struct AvailHeadData { start: u64, end: u64, } ``` * Run the code using: ```bash cargo run ``` ## Send an arbitrary message from Ethereum to Avail DA #### avail-rust Let us look at how a message sent from Ethereum is being executed on Avail using the `vector` pallet. ```rust let da_call = avail::tx().vector().execute( avail_stored_slot, convert_addressed_message(sent_message), acc_proof, stor_proof, ); ``` ## Full Example ### Sending arbitrary message from Ethereum to Avail Let us initialize some of out essentials such as `signer`, `provider`, `contract`, etc. This will allow us to interact with Ethereum easily. ```rust use alloy::primitives::Address; use alloy_network::EthereumWallet; use alloy_provider::ProviderBuilder; use alloy_sol_types::sol; use anyhow::{anyhow, Result}; use avail_bridge_tools::{address_to_h256, convert_addressed_message, eth_seed_to_address, Config}; use avail_rust::avail::runtime_types::bounded_collections::bounded_vec::BoundedVec; use avail_rust::avail_core::data_proof::AddressedMessage; use avail_rust::{avail, AvailExtrinsicParamsBuilder, Keypair, SecretUri, WaitFor, SDK}; use reqwest::Url; use serde::{Deserialize, Deserializer}; use sp_core::H256; use std::fs; use std::str::FromStr; use std::time::Duration; sol!( #[sol(rpc)] AvailBridgeContract, "src/availbridge.json" ); #[tokio::main] async fn main() -> Result<()> { let content = fs::read_to_string("./config.toml").expect("Read config.toml"); let config = toml::from_str::(&content).expect("Parse config.toml"); let secret_uri = SecretUri::from_str(config.avail_mnemonic.as_str()) .expect("parse avail sender mnemonic"); let account = Keypair::from_uri(&secret_uri).expect("create keypair"); let recipient = account.public_key().0; let ethereum_signer = config .ethereum_mnemonic .parse::()?; let sender = eth_seed_to_address(config.ethereum_mnemonic.as_str()); let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(EthereumWallet::from(ethereum_signer)) .on_http(Url::parse(config.ethereum_url.as_str())?); let contract_addr: Address = config.contract_address.parse()?; let contract = AvailBridgeContract::new(contract_addr, &provider); } ``` 2. Now we send a message using `contract.sendMessage` from Ethereum to Avail. ```rust let call = contract.sendMessage(recipient.into(), config.clone().message_data.into()); let pending_tx = call.from(sender.0.into()); let pending_tx = pending_tx.send().await?; let receipt = pending_tx.get_receipt().await?; let block_number = receipt.block_number.ok_or(anyhow!("No block number!"))?; println!("Included in block no: {block_number}"); let logs = receipt .inner .as_receipt() .ok_or(anyhow!("Cannot convert to receipt"))? .logs .clone(); assert!(!logs.is_empty(), "Logs are empty!"); let message_id = u64::from_be_bytes( logs[0].clone().inner.data.data[32 - 8..] .try_into() .unwrap(), ); let sent_message = AddressedMessage { message: avail_rust::avail_core::data_proof::Message::ArbitraryMessage( config.message_data.as_bytes().to_vec().try_into().unwrap(), ), from: address_to_h256(sender), to: H256(recipient), origin_domain: 2, destination_domain: 1, id: message_id, }; ``` ### Retrieving and Executing the message sent to Avail 1. Using the Bridge API we check if the Ethereum block in which we sent the message is in range for the bridge. If it is, then we get the account and storage proofs. ```rust let (avail_stored_block_hash, avail_stored_slot) = loop { let ethereum_slot_info: EthereumSlotInfo = reqwest::get(format!("{}/eth/head", config.bridge_api_url)) .await .unwrap() .json() .await?; println!("New slot: {ethereum_slot_info:?}"); let block_info: BlockInfo = reqwest::get(format!( "{}/beacon/slot/{}", config.bridge_api_url, ethereum_slot_info.slot )) .await .unwrap() .json() .await?; println!("Slot to block number: {}", block_info.block_number); if block_info.block_number >= block_number { println!("Stored eth head is in range!"); break (block_info.block_hash, ethereum_slot_info.slot); } tokio::time::sleep(Duration::from_secs(60)).await; }; let account_storage_proof: AccountStorageProof = reqwest::get(format!( "{}/avl/proof/{:?}/{}", config.bridge_api_url, avail_stored_block_hash, message_id )) .await .expect("Cannot get account/storage proofs.") .json() .await .expect("Cannot deserialize"); println!("Got proof! {account_storage_proof:?}"); let acc_proof = BoundedVec( account_storage_proof .account_proof .into_iter() .map(BoundedVec) .collect::>(), ); let stor_proof = BoundedVec( account_storage_proof .storage_proof .into_iter() .map(BoundedVec) .collect::>(), ); println!("Message: {sent_message:?}"); let sdk = SDK::new(config.avail_rpc_url.as_str()) .await .expect("create sdk"); ``` 2. We then call in Avail to call the `execute` method in the `vector` pallet, which is for executing a bridged message from Ethereum. We are submitting proof against the roots stored in the pallet storage. The pallet then executes the message we are giving proof for. We only get the encoded tx, that we then have to sign and send, and wait for the transaction to included and executed on Avail. ```rust let da_call = avail::tx().vector().execute( avail_stored_slot, convert_addressed_message(sent_message), acc_proof, stor_proof, ); let params = AvailExtrinsicParamsBuilder::new().build(); let maybe_tx_progress = sdk .api .tx() .sign_and_submit_then_watch(&da_call, &account, params) .await; let transaction = sdk .util .progress_transaction(maybe_tx_progress, WaitFor::BlockFinalization) .await; let tx_in_block = match transaction { Ok(tx_in_block) => tx_in_block, Err(message) => { panic!("Error: {}", message); } }; println!("Finalized block hash: {:?}", tx_in_block.block_hash()); ``` *** Bringing it all together in `src/main.rs`: ```rust use alloy::primitives::Address; use alloy_network::EthereumWallet; use alloy_provider::ProviderBuilder; use alloy_sol_types::sol; use anyhow::{anyhow, Result}; use avail_bridge_tools::{address_to_h256, convert_addressed_message, eth_seed_to_address, Config}; use avail_rust::avail::runtime_types::bounded_collections::bounded_vec::BoundedVec; use avail_rust::avail_core::data_proof::AddressedMessage; use avail_rust::{avail, AvailExtrinsicParamsBuilder, Keypair, SecretUri, WaitFor, SDK}; use reqwest::Url; use serde::{Deserialize, Deserializer}; use sp_core::H256; use std::fs; use std::str::FromStr; use std::time::Duration; sol!( #[sol(rpc)] AvailBridgeContract, "src/availbridge.json" ); #[tokio::main] async fn main() -> Result<()> { let content = fs::read_to_string("./config.toml").expect("Read config.toml"); let config = toml::from_str::(&content).expect("Parse config.toml"); let secret_uri = SecretUri::from_str(config.avail_mnemonic.as_str()) .expect("parse avail sender mnemonic"); let account = Keypair::from_uri(&secret_uri).expect("create keypair"); let recipient = account.public_key().0; let ethereum_signer = config .ethereum_mnemonic .parse::()?; let sender = eth_seed_to_address(config.ethereum_mnemonic.as_str()); let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(EthereumWallet::from(ethereum_signer)) .on_http(Url::parse(config.ethereum_url.as_str())?); let contract_addr: Address = config.contract_address.parse()?; let contract = AvailBridgeContract::new(contract_addr, &provider); let call = contract.sendMessage(recipient.into(), config.clone().message_data.into()); let pending_tx = call.from(sender.0.into()); let pending_tx = pending_tx.send().await?; let receipt = pending_tx.get_receipt().await?; let block_number = receipt.block_number.ok_or(anyhow!("No block number!"))?; println!("Included in block no: {block_number}"); let logs = receipt .inner .as_receipt() .ok_or(anyhow!("Cannot convert to receipt"))? .logs .clone(); assert!(!logs.is_empty(), "Logs are empty!"); let message_id = u64::from_be_bytes( logs[0].clone().inner.data.data[32 - 8..] .try_into() .unwrap(), ); let sent_message = AddressedMessage { message: avail_rust::avail_core::data_proof::Message::ArbitraryMessage( config.message_data.as_bytes().to_vec().try_into().unwrap(), ), from: address_to_h256(sender), to: H256(recipient), origin_domain: 2, destination_domain: 1, id: message_id, }; let (avail_stored_block_hash, avail_stored_slot) = loop { let ethereum_slot_info: EthereumSlotInfo = reqwest::get(format!("{}/eth/head", config.bridge_api_url)) .await .unwrap() .json() .await?; println!("New slot: {ethereum_slot_info:?}"); let block_info: BlockInfo = reqwest::get(format!( "{}/beacon/slot/{}", config.bridge_api_url, ethereum_slot_info.slot )) .await .unwrap() .json() .await?; println!("Slot to block number: {}", block_info.block_number); if block_info.block_number >= block_number { println!("Stored eth head is in range!"); break (block_info.block_hash, ethereum_slot_info.slot); } tokio::time::sleep(Duration::from_secs(60)).await; }; let account_storage_proof: AccountStorageProof = reqwest::get(format!( "{}/avl/proof/{:?}/{}", config.bridge_api_url, avail_stored_block_hash, message_id )) .await .expect("Cannot get account/storage proofs.") .json() .await .expect("Cannot deserialize"); println!("Got proof! {account_storage_proof:?}"); let acc_proof = BoundedVec( account_storage_proof .account_proof .into_iter() .map(BoundedVec) .collect::>(), ); let stor_proof = BoundedVec( account_storage_proof .storage_proof .into_iter() .map(BoundedVec) .collect::>(), ); println!("Message: {sent_message:?}"); let sdk = SDK::new(config.avail_rpc_url.as_str()) .await .expect("create sdk"); let da_call = avail::tx().vector().execute( avail_stored_slot, convert_addressed_message(sent_message), acc_proof, stor_proof, ); let params = AvailExtrinsicParamsBuilder::new().build(); let maybe_tx_progress = sdk .api .tx() .sign_and_submit_then_watch(&da_call, &account, params) .await; let transaction = sdk .util .progress_transaction(maybe_tx_progress, WaitFor::BlockFinalization) .await; let tx_in_block = match transaction { Ok(tx_in_block) => tx_in_block, Err(message) => { panic!("Error: {}", message); } }; println!("Finalized block hash: {:?}", tx_in_block.block_hash()); Ok(()) } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct BlockInfo { block_number: u64, block_hash: H256, } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct EthereumSlotInfo { pub slot: u64, pub _timestamp: u64, pub _timestamp_diff: u64, } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct AccountStorageProof { #[serde(deserialize_with = "bytes_from_hex")] account_proof: Vec>, #[serde(deserialize_with = "bytes_from_hex")] storage_proof: Vec>, } fn bytes_from_hex<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, { let buf = >::deserialize(deserializer)?; let res = buf .iter() .map(|e| { let without_prefix = e.trim_start_matches("0x"); hex::decode(without_prefix).unwrap() }) .collect::>(); Ok(res) } ``` Run the code using: ```bash cargo run ``` ### Bridge tokens from origin to destination chain * On-chain name of extrinsic: `vector_sendMessage` to send a message from Avail to Ethereum. * On-chain name of extrinsic: `vector_execute` to execute a message receieved from Ethereum on Avail. ## Bridge tokens from Avail DA to Ethereum ## Bridge tokens from Ethereum to Avail DA #### avail-rust Let us look at how a message sent from Ethereum is being executed on Avail using the `vector` pallet. ```rust let da_call = avail::tx().vector().execute( avail_stored_slot, convert_addressed_message(sent_message), acc_proof, stor_proof, ); ``` ## Full Example ### Sending AVAIL tokens from Ethereum to Avail Let us initialize some of out essentials such as `signer`, `provider`, `contract`, etc. This will allow us to interact with Ethereum easily. ```rust use alloy::primitives::{Address, U256}; use alloy_network::EthereumWallet; use alloy_provider::ProviderBuilder; use alloy_sol_types::sol; use anyhow::{anyhow, Result}; use avail_bridge_tools::{address_to_h256, convert_addressed_message, eth_seed_to_address, Config}; use avail_rust::avail::runtime_types::bounded_collections::bounded_vec::BoundedVec; use avail_rust::avail_core::data_proof::AddressedMessage; use avail_rust::{avail, AvailExtrinsicParamsBuilder, WaitFor, SDK}; use avail_rust::{subxt_signer::SecretUri, Keypair}; use reqwest::Url; use serde::{Deserialize, Deserializer}; use sp_core::H256; use std::{fs, str::FromStr, time::Duration}; sol!( #[sol(rpc)] AvailBridgeContract, "src/availbridge.json" ); #[tokio::main] async fn main() -> Result<()> { let content = fs::read_to_string("./config.toml").expect("Read config.toml"); let config = toml::from_str::(&content).unwrap(); let secret_uri = SecretUri::from_str(config.avail_mnemonic.as_str()).expect("Valid secret URI"); let account = Keypair::from_uri(&secret_uri).expect("Valid secret URI"); let recipient = account.public_key().0; let amount: u128 = 100000; let ethereum_signer = config .ethereum_mnemonic .parse::()?; let sender = eth_seed_to_address(config.ethereum_mnemonic.as_str()); let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(EthereumWallet::from(ethereum_signer)) .on_http(Url::parse(config.ethereum_url.as_str())?); ``` 2. Now we send a message using `contract.sendAVAIL` from Ethereum to Avail. ```rust let contract = AvailBridgeContract::new(contract_addr, &provider); let call = contract.sendAVAIL(recipient.into(), U256::from(amount)); let pending_tx = call.from(sender.0.into()); let pending_tx = pending_tx.send().await?; let receipt = pending_tx.get_receipt().await?; let block_number = receipt.block_number.ok_or(anyhow!("No block number!"))?; println!("Included in block no: {block_number}"); let logs = receipt .inner .as_receipt() .ok_or(anyhow!("Cannot convert to receipt"))? .logs .clone(); assert!(!logs.is_empty(), "Logs are empty!"); ``` 3. Let us also define our `message_id` and define the parameters of our AVAIL that is being sent to be understandable by the Avail network, such as `message.asset_id`, `message.amount`, `from` addressm `to` address, `origin_domain` (Ethereum), `destination_domain` (Avail) ```rust let message_id = u64::from_be_bytes( logs[0].clone().inner.data.data[32 - 8..] .try_into() .unwrap(), ); let sent_message = AddressedMessage { message: avail_rust::avail_core::data_proof::Message::FungibleToken { asset_id: H256::zero(), amount, }, from: address_to_h256(sender), to: H256(recipient), origin_domain: 2, destination_domain: 1, id: message_id, }; ``` ### Retrieving and Executing the message sent to Avail 1. Using the Bridge API we check if the Ethereum block in which we sent the message is in range for the bridge. If it is, then we get the account and storage proofs. ```rust let (avail_stored_block_hash, avail_stored_slot) = loop { let ethereum_slot_info: EthereumSlotInfo = reqwest::get(format!("{}/eth/head", config.bridge_api_url)) .await .unwrap() .json() .await?; println!("New slot: {ethereum_slot_info:?}"); let block_info: BlockInfo = reqwest::get(format!( "{}/beacon/slot/{}", config.bridge_api_url, ethereum_slot_info.slot )) .await .unwrap() .json() .await?; println!("Slot to num: {}", block_info.block_number); if block_info.block_number >= block_number { println!("Stored eth head is in range!"); break (block_info.block_hash, ethereum_slot_info.slot); } tokio::time::sleep(Duration::from_secs(60)).await; }; let account_storage_proof: AccountStorageProof = reqwest::get(format!( "{}/avl/proof/{:?}/{}", config.bridge_api_url, avail_stored_block_hash, message_id )) .await .expect("Cannot get account/storage proofs.") .json() .await .expect("Cannot deserialize"); println!("Got proof! {account_storage_proof:?}"); let acc_proof = BoundedVec( account_storage_proof .account_proof .into_iter() .map(BoundedVec) .collect::>(), ); let stor_proof = BoundedVec( account_storage_proof .storage_proof .into_iter() .map(BoundedVec) .collect::>(), ); println!("Message: {sent_message:?}"); ``` 2. We then initialize the Avail SDK and call the `execute` method in the `vector` pallet, which is for executing a bridged message from Ethereum. We are submitting proof against the roots stored in the pallet storage. The pallet then executes the message we are giving proof for. We only get the encoded tx, that we then have to sign and send, and wait for the transaction to included and executed on Avail. ```rust let sdk = SDK::new(config.avail_rpc_url.as_str()).await.unwrap(); let da_call = avail::tx().vector().execute( avail_stored_slot, convert_addressed_message(sent_message), acc_proof, stor_proof, ); let params = AvailExtrinsicParamsBuilder::new().build(); let maybe_tx_progress = sdk .api .tx() .sign_and_submit_then_watch(&da_call, &account, params) .await; let transaction = sdk .util .progress_transaction(maybe_tx_progress, WaitFor::BlockFinalization) .await; let tx_in_block = match transaction { Ok(tx_in_block) => tx_in_block, Err(message) => { panic!("Error: {}", message); } }; println!("Executed at block: {:?}", tx_in_block.block_hash()); ``` *** * Bringing it all together in `src/main.rs`: ```rust use alloy::primitives::{Address, U256}; use alloy_network::EthereumWallet; use alloy_provider::ProviderBuilder; use alloy_sol_types::sol; use anyhow::{anyhow, Result}; use avail_bridge_tools::{address_to_h256, convert_addressed_message, eth_seed_to_address, Config}; use avail_rust::avail::runtime_types::bounded_collections::bounded_vec::BoundedVec; use avail_rust::avail_core::data_proof::AddressedMessage; use avail_rust::{avail, AvailExtrinsicParamsBuilder, WaitFor, SDK}; use avail_rust::{subxt_signer::SecretUri, Keypair}; use reqwest::Url; use serde::{Deserialize, Deserializer}; use sp_core::H256; use std::{fs, str::FromStr, time::Duration}; sol!( #[sol(rpc)] AvailBridgeContract, "src/availbridge.json" ); #[tokio::main] async fn main() -> Result<()> { let content = fs::read_to_string("./config.toml").expect("Read config.toml"); let config = toml::from_str::(&content).unwrap(); let secret_uri = SecretUri::from_str(config.avail_mnemonic.as_str()).expect("Valid secret URI"); let account = Keypair::from_uri(&secret_uri).expect("Valid secret URI"); let recipient = account.public_key().0; let amount: u128 = 100000; let ethereum_signer = config .ethereum_mnemonic .parse::()?; let sender = eth_seed_to_address(config.ethereum_mnemonic.as_str()); let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(EthereumWallet::from(ethereum_signer)) .on_http(Url::parse(config.ethereum_url.as_str())?); let contract_addr: Address = config.contract_address.parse()?; let contract = AvailBridgeContract::new(contract_addr, &provider); let call = contract.sendAVAIL(recipient.into(), U256::from(amount)); let pending_tx = call.from(sender.0.into()); let pending_tx = pending_tx.send().await?; let receipt = pending_tx.get_receipt().await?; let block_number = receipt.block_number.ok_or(anyhow!("No block number!"))?; println!("Included in block no: {block_number}"); let logs = receipt .inner .as_receipt() .ok_or(anyhow!("Cannot convert to receipt"))? .logs .clone(); assert!(!logs.is_empty(), "Logs are empty!"); let message_id = u64::from_be_bytes( logs[0].clone().inner.data.data[32 - 8..] .try_into() .unwrap(), ); let sent_message = AddressedMessage { message: avail_rust::avail_core::data_proof::Message::FungibleToken { asset_id: H256::zero(), amount, }, from: address_to_h256(sender), to: H256(recipient), origin_domain: 2, destination_domain: 1, id: message_id, }; let (avail_stored_block_hash, avail_stored_slot) = loop { let ethereum_slot_info: EthereumSlotInfo = reqwest::get(format!("{}/eth/head", config.bridge_api_url)) .await .unwrap() .json() .await?; println!("New slot: {ethereum_slot_info:?}"); let block_info: BlockInfo = reqwest::get(format!( "{}/beacon/slot/{}", config.bridge_api_url, ethereum_slot_info.slot )) .await .unwrap() .json() .await?; println!("Slot to num: {}", block_info.block_number); if block_info.block_number >= block_number { println!("Stored eth head is in range!"); break (block_info.block_hash, ethereum_slot_info.slot); } tokio::time::sleep(Duration::from_secs(60)).await; }; let account_storage_proof: AccountStorageProof = reqwest::get(format!( "{}/avl/proof/{:?}/{}", config.bridge_api_url, avail_stored_block_hash, message_id )) .await .expect("Cannot get account/storage proofs.") .json() .await .expect("Cannot deserialize"); println!("Got proof! {account_storage_proof:?}"); let acc_proof = BoundedVec( account_storage_proof .account_proof .into_iter() .map(BoundedVec) .collect::>(), ); let stor_proof = BoundedVec( account_storage_proof .storage_proof .into_iter() .map(BoundedVec) .collect::>(), ); println!("Message: {sent_message:?}"); let sdk = SDK::new(config.avail_rpc_url.as_str()).await.unwrap(); let da_call = avail::tx().vector().execute( avail_stored_slot, convert_addressed_message(sent_message), acc_proof, stor_proof, ); let params = AvailExtrinsicParamsBuilder::new().build(); let maybe_tx_progress = sdk .api .tx() .sign_and_submit_then_watch(&da_call, &account, params) .await; let transaction = sdk .util .progress_transaction(maybe_tx_progress, WaitFor::BlockFinalization) .await; let tx_in_block = match transaction { Ok(tx_in_block) => tx_in_block, Err(message) => { panic!("Error: {}", message); } }; println!("Executed at block: {:?}", tx_in_block.block_hash()); Ok(()) } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct BlockInfo { block_number: u64, block_hash: H256, } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct EthereumSlotInfo { pub slot: u64, pub _timestamp: u64, pub _timestamp_diff: u64, } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct AccountStorageProof { #[serde(deserialize_with = "bytes_from_hex")] account_proof: Vec>, #[serde(deserialize_with = "bytes_from_hex")] storage_proof: Vec>, } fn bytes_from_hex<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, { let buf = >::deserialize(deserializer)?; let res = buf .iter() .map(|e| { let without_prefix = e.trim_start_matches("0x"); hex::decode(without_prefix).unwrap() }) .collect::>(); Ok(res) } ``` * Run the code using: ```bash cargo run ``` ### V1 Deprecated > **Warning** > > **The V1 Light Client API has been deprecated.** > All V1 endpoints have equivalent V2 replacements. Please migrate to the [V2 API](/docs/da/api-reference/avail-lc-api). ## What replaced it The V2 API is a backward-compatible upgrade that preserves all V1 functionality while adding WebSocket support for real-time subscriptions and selective field queries for more efficient data retrieval. ## How to migrate Change `/v1/` to `/v2/` in your endpoint paths. All V1 endpoints have direct V2 equivalents: | V1 endpoint | V2 equivalent | | ----------------------- | ----------------------------------------------- | | `/v1/version` | `GET /v2/version` | | `/v1/status` | `GET /v2/status` | | `/v1/blocks/{n}` | `GET /v2/blocks/{n}` | | `/v1/blocks/{n}/header` | `GET /v2/blocks/{n}/header` | | `/v1/blocks/{n}/data` | `GET /v2/blocks/{n}/data?fields=data,extrinsic` | | `/v1/submit` | `POST /v2/submit` | ### New in V2 * **WebSocket API** — real-time subscriptions for block and data availability events * **Selective field queries** — request only the fields you need (e.g., `?fields=data,extrinsic`) See the [V2 API reference](/docs/da/api-reference/avail-lc-api) for full endpoint documentation. ### Fetch specified block status and confidence if applicable > **Note** > > **LOOKING FOR INSTRUCTIONS ON HOW TO RUN YOUR OWN LIGHT CLIENT?** > You can check out [our docs here](/docs/da/operate/run-a-light-client/light-client#running-the-light-client) for instructions on how to run your own light client. Gets specified block status and confidence if applicable. **Use cases:** * Polling the status of the block * Querying historical block statuses *Params*: * `block_number` - block number (required) *Response*: * **status** - block status * **confidence** - data availability confidence, available if block processing is finished. #### Status * **unavailable** - block will not be processed if \ **latest\_block - sync\_depth > block\_number** * **pending** - block will be processed at some point in the future if \ **latest\_block - sync\_depth ≤ block\_number ≤ latest\_block** * **verifying-header** - block processing is started, and the header finality is being checked * **verifying-confidence** - block header is verified and available, confidence is being checked * **verifying-data** - confidence is achieved, and data is being fetched and verified (if configured) * **finished** - block header is available, confidence is achieved, and data is available (if configured) This status does not give information on what is available. In the case of web sockets messages are already pushed, similar to case of the frequent polling, so header and confidence will be available if **verifying-header** and **verifying-confidence** has been successful. #### CURL ```bash filename="CURL" curl "localhost:7007/v2/blocks/{insert a suitable block number}" ``` #### Rust ```bash filename="CURL" curl "https://api.lightclient.mainnet.avail.so/v2/blocks/{insert a suitable block number}" ``` ```rust use reqwest::StatusCode; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] enum BlockResponse { NotFound(String), BlockStatus { status: String, confidence: Option, }, } const LIGHT_CLIENT_URL: &str = "https://api.lightclient.mainnet.avail.so"; #[tokio::main] async fn main() { let block_number = 672481; // Example block number let block_url = format!("{LIGHT_CLIENT_URL}/v2/blocks/{block_number}"); let response = reqwest::get(&block_url).await.unwrap(); if response.status() == StatusCode::OK { let response_text = response.text().await.unwrap(); println!("Raw response: {}", response_text); let block_info: BlockResponse = serde_json::from_str(&response_text).unwrap(); match block_info { BlockResponse::NotFound(message) => println!("Block status: {}", message), BlockResponse::BlockStatus { status, confidence, } => println!( "Block status: {}, Confidence: {:?}", status, confidence.unwrap_or_default() ), } } else { eprintln!("Failed to get block status: {}", response.status()); } // ...error handling... } ```
Sample Response: ```json { "status": "unavailable|pending|verifying-header|verifying-confidence|verifying-data|incomplete|finished", "confidence": {confidence} // Optional } ```
> If **block\_number > latest\_block,** block status cannot yet be derived and the response on this and other endpoints with `/v2/blocks/{block_number}` prefix is: ```yaml Not Found ``` ### Fetch the header for a specific block if available > **Note** > > **LOOKING FOR INSTRUCTIONS ON HOW TO RUN YOUR OWN LIGHT CLIENT?** > You can check out [our docs here](/docs/da/operate/run-a-light-client/light-client#running-the-light-client) for instructions on how to run your own light client. Gets the header for a specifc block if available. *Params*: * `block_number` - block number (required) *Response*: If **block\_status = "verifying-confidence|verifying-data|finished"**, the header is available, and the response is: ```yaml HTTP/1.1 200 OK Content-Type: application/json { "hash": "{hash}", "parent_hash": "{parent-hash}", "number": {number}, "state_root": "{state-root}", "extrinsics_root": "{extrinsics-root}", "extension": { "rows": {rows}, "cols": {cols}, "data_root": "{data-root}", // Optional "commitments": [ "{commitment}", ... ], "app_lookup": { "size": {size}, "index": [ { "app_id": {app-id}, "start": {start} } ] } } } ``` If **block\_status = "unavailable|pending|verifying-header"**, header is not available and response is: ```yaml HTTP/1.1 400 Bad Request ``` #### CURL ```bash filename="CURL" curl "localhost:7007/v2/blocks/{insert a suitable block number}/header" ``` #### Rust ```bash filename="CURL" curl "https://api.lightclient.mainnet.avail.so/v2/blocks/{insert a suitable block number}/header" ``` ```rust use reqwest::{StatusCode, Client}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct BlockHeaderResponse { hash: String, parent_hash: String, number: u32, state_root: String, extrinsics_root: String, extension: Extension, } #[derive(Debug, Serialize, Deserialize)] struct Extension { rows: u32, cols: u32, data_root: Option, commitments: Vec, app_lookup: AppLookup, } #[derive(Debug, Serialize, Deserialize)] struct AppLookup { size: u32, index: Vec, } #[derive(Debug, Serialize, Deserialize)] struct AppIndex { app_id: Option, start: u32, } const LIGHT_CLIENT_URL: &str = "https://api.lightclient.mainnet.avail.so"; #[tokio::main] async fn main() { let block_number = 592445; // Example block number let client = Client::new(); let header_url = format!("{LIGHT_CLIENT_URL}/v2/blocks/{block_number}/header"); let response = client.get(header_url).send().await.unwrap(); match response.status() { StatusCode::OK => { let block_header: BlockHeaderResponse = response.json().await.unwrap(); println!("Block header: {:?}", block_header); } StatusCode::BAD_REQUEST => { println!("Header not available for block {}", block_number); } _ => { eprintln!("Failed to get block header: {}", response.status()); } } // ...error handling... } ``` ### Fetch block data if available > **Note** > > **LOOKING FOR INSTRUCTIONS ON HOW TO RUN YOUR OWN LIGHT CLIENT?** > You can check out [our docs here](/docs/da/operate/run-a-light-client/light-client#running-the-light-client) for instructions on how to run your own light client. > **Warning** > > **Note:** > Light client must be running in `app-mode`to retrieve data. [Click here](/docs/da/operate/run-a-light-client/light-client#setting-your-identity-using-identitytoml) for instructions on how to run an Avail Light Client in `app-mode`. Gets the block data if available. Only returns data if the block contains it for the configured `app_id`. If there is no data against the configured `app_id` it returns an empty array. Query parameter `fields` specifies whether to return decoded data and encoded extrinsic (with signature). If `fields` parameter is omitted, response contains **hash** and **data**, while **extrinsic** is omitted. The `data` and `extrinsic` is encoded in `base64` format. #### CURL ```sh curl "localhost:7007/v2/blocks/{block_number}/data?fields=data,extrinsic" ``` #### Rust ```sh curl "https://api.lightclient.mainnet.avail.so/v2/blocks/{block_number}/data?fields=data,extrinsic" ``` ```rust use reqwest::{Client, StatusCode}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct BlockDataResponse { data_transactions: Vec, } #[derive(Debug, Serialize, Deserialize)] struct DataTransaction { data: Option, // Base-64 encoded data (optional) extrinsic: Option, // Base-64 encoded extrinsic (optional) } const LIGHT_CLIENT_URL: &str = "https://api.lightclient.mainnet.avail.so"; #[tokio::main] async fn main() { let block_number = 592445; // Example block number let client = Client::new(); let data_url = format!("{LIGHT_CLIENT_URL}/v2/blocks/{block_number}/data?fields=data,extrinsic"); let response = client.get(&data_url).send().await.unwrap(); match response.status() { StatusCode::OK => { let block_data: BlockDataResponse = response.json().await.unwrap(); println!("Block data: {:?}", block_data); } StatusCode::BAD_REQUEST => { println!("Data not available for block {}", block_number); } _ => { eprintln!("Failed to get block data: {}", response.status()); } } // ...error handling... } ```
Sample Response: If **block\_status = "finished"**, data is available and the response is: ```yaml { "data_transactions": [ { "data": "{base-64-encoded-data}" // Optional "extrinsic": "{base-64-encoded-extrinsic}", // Optional } ] } ``` If **block\_status** is not **“finished”**, or **`app-mode`** is not enabled, data is not available and the response is: ```yaml Not Found ``` If no data is available in the block against the configured `app_id` in `app-mode`: ```yaml { "data_transactions": [] } ```
> **Note** > > The next few methods are used to submit data to the Avail network. But to use them: > > 1. you need to configure an `identity.toml` file which will contain the seed phrase > for an account that has some `AVAIL` tokens. You can learn how to do that [here](/docs/da/operate/run-a-light-client/light-client#setting-your-identity-using-identitytoml). > > 2. You will also need to run the Avail LC in app-client mode. The command to do all this will > look something like this: > > ```sh > curl -sL1 avail.sh | bash -s -- --app_id 1 --identity identity.toml --network mainnet > ``` ### Fetch current status and active modes of the light client > **Note** > > **LOOKING FOR INSTRUCTIONS ON HOW TO RUN YOUR OWN LIGHT CLIENT?** > You can check out [our docs here](/docs/da/operate/run-a-light-client/light-client#running-the-light-client) for instructions on how to run your own light client. Gets current status and active modes of the light client. *Params*: * None *Response*: * **modes** - active modes * **app\_id** - if **app** mode is active, this field contains configured application ID * **genesis\_hash** - genesis hash of the network to which the light client is connected * **network** - network host, version and spec version light client is currently con * **blocks** - state of processed blocks #### Modes * **light** - data availability sampling mode, the light client performs random sampling and calculates confidence * **app** - light client fetches, verifies, and stores application-related data #### Blocks * **latest** - block number of the latest [finalized](https://docs.substrate.io/learn/consensus/) block received from the node * **available** - range of blocks with verified data availability (configured confidence has been achieved) * **app\_data** - range of blocks with app data retrieved and verified * **historical\_sync** - state for historical blocks syncing up to configured block (ommited if historical sync is not configured) #### Historical sync * **synced** - `true` if there are no historical blocks left to sync * **available** - range of historical blocks with verified data availability (configured confidence has been achieved) * **app\_data** - range of historical blocks with app data retrieved and verified #### CURL ```bash filename="CURL" curl "localhost:7007/v2/status" ``` #### Rust ```bash filename="CURL" curl "https://api.lightclient.mainnet.avail.so/v2/status" ``` ```rust use reqwest::StatusCode; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct StatusResponse { modes: Vec, app_id: Option, genesis_hash: String, network: String, blocks: Blocks, partition: Option, } #[derive(Debug, Serialize, Deserialize)] struct Blocks { latest: u32, available: Range, app_data: Option, historical_sync: Option, } #[derive(Debug, Serialize, Deserialize)] struct Range { first: u32, last: u32, } #[derive(Debug, Serialize, Deserialize)] struct HistoricalSync { synced: bool, available: Range, app_data: Range, } #[derive(Debug, Serialize, Deserialize)] struct Partition { // Define fields as per your requirement } const LIGHT_CLIENT_URL: &str = "https://api.lightclient.mainnet.avail.so"; #[tokio::main] async fn main() { let status_url = format!("{LIGHT_CLIENT_URL}/v2/status"); let response = reqwest::get(&status_url).await.unwrap(); if response.status() == StatusCode::OK { let response_text = response.text().await.unwrap(); println!("Raw response: {}", response_text); let status_info: StatusResponse = serde_json::from_str(&response_text).unwrap(); println!("Status: {:?}", status_info); } else { eprintln!("Failed to get status: {}", response.status()); } // ...error handling... } ```
Sample Response: ```json { "modes":["light"], "genesis_hash":"0x6f09966420b2608d1947ccfb0f2a362450d1fc7fd902c29b67c906eaa965a7ae", "network":"wss://goldberg.avail.tools:443/ws/1.11.1-38304bb5126/data-avail/22", "blocks":{ "latest":572269, "available":{ "first":572068, "last":572268 } } } ```
### Submit data to Avail DA > **Note** > > **LOOKING FOR INSTRUCTIONS ON HOW TO RUN YOUR OWN LIGHT CLIENT?** > You can check out [our docs here](/docs/da/operate/run-a-light-client/light-client#running-the-light-client) for instructions on how to run your own light client. > **Warning** > > **Note:** > Light client must be running in `app-mode`to retrieve data. [Click here](/docs/da/operate/run-a-light-client/light-client#setting-your-identity-using-identitytoml) for instructions on how to run an Avail Light Client in `app-mode`. > Submits application data to the avail network In case of `data` transaction, data transaction is created, signed and submitted.\ In case of `extrinsic`, externally created and signed transaction is submitted. Only one field is allowed per request.\ Both `data` and `extrinsic` has to be encoded using base64 encoding. *Params:* * `base64` encoded data or extrinsic > **Note** > > **HOW TO SUBMIT DATA USING THE LIGHT CLIENT?** > > 1. To use this method you need to run your Light Client in the `app-client` mode. > You can then submit data directly to the `appID` you configured while booting up the Light Client. > > 2. You can only pass `Base64` encoded data to be submitted via the Light Client. > You can use [this website](https://www.base64encode.org/) to encode & decode your data into the required formats. *Response:* * **block\_number** - block number where transaction is included * **block\_hash** - block hash where transaction is included * **hash** - transaction hash * **index** - transaction index in the block #### CURL ```bash filename="CURL" curl -XPOST 127.0.0.1:7007/v2/submit --header "Content-Type: application/json" --data '{"data":"dGVzdAo="}' ``` #### Rust ```rust use reqwest::{Client, StatusCode}; use serde::{Deserialize, Serialize}; use serde_json::json; #[derive(Debug, Serialize, Deserialize)] struct SubmitResponse { block_number: u32, block_hash: String, hash: String, index: u32, } const LIGHT_CLIENT_URL: &str = "https://api.lightclient.mainnet.avail.so"; #[tokio::main] async fn main() { let client = Client::new(); let submit_url = format!("{LIGHT_CLIENT_URL}/v2/submit"); let data = "dGVzdAo="; // Example base64 encoded data let response = client.post(&submit_url) .header("Content-Type", "application/json") .body(json!({ "data": data }).to_string()) .send() .await .unwrap(); match response.status() { StatusCode::OK => { let submit_response: SubmitResponse = response.json().await.unwrap(); println!("Submit response: {:?}", submit_response); } StatusCode::NOT_FOUND => { println!("App mode not active or signing key not configured."); } _ => { eprintln!("Failed to submit data: {}", response.status()); } } // ...error handling... } ```
Sample Response: ```json { "block_number": "{block-number}", "block_hash": "{block-hash}", "hash": "{transaction-hash}", "index": "{transaction-index}" } ``` If app mode is not active (or signing key is not configured and `data` is submitted) response is: ```text Not found ```
### WebSocket API The Avail light client WebSocket API allows real-time communication between a client and a server over a persistent connection. The Web socket API can be used on its own or in combination with HTTP API to enable different pull/push use cases.
HTTPS vs WSS `HTTP` and `Websocket` are two different ways of communicating with a server. `HTTP` is a request-response protocol, where a connection persists for only so long as the request is being processed. In contrast, a websocket connection persists for as long as the client and server are connected. This allows for real-time communication between the two, and enables the client to fetch information from the server as soon as it is available, without having to poll the server for updates.
> **Note** > > HOW TO CONNECT TO THE WEBSOCKET SERVER > You cannot use `CURL` to send websocket commands, since `CURL` cannot maintain a persistent connection. > Although there are a variety of librariries we can use, the following examples are using [wscat](https://github.com/websockets/wscat). > > To install `wscat`, simply run: > > ```sh > npm install -g wscat > ``` ## Get started with the Websocket Avail LC API 1. The Avail LC Websocket API generates a unique `subscription_id` upon request. 2. This ID is used to connect to the websocket server. 3. The `v2/subscriptions` method creates subscriptions for given topics. In case of reconnects, the user needs to subscribe again. ### Generate a subscription ID 1. The very first step in using the Avail LC Websocket API is to generate a subscription ID. 2. You can do that using a simple `Curl` request to the `v2/subscriptions` endpoint. Request: #### CURL ```bash filename="CURL" curl -X POST "http://localhost:7007/v2/subscriptions" \ -H "Content-Type: application/json" \ -d '{ "topics": ["header-verified", "confidence-achieved", "data-verified"], "data_fields": ["data", "extrinsic"] }' ``` #### Rust ```bash filename="CURL" curl -X POST "https://api.lightclient.mainnet.avail.so/v2/subscriptions" \ -H "Content-Type: application/json" \ -d '{ "topics": ["header-verified", "confidence-achieved", "data-verified"], "data_fields": ["data", "extrinsic"] }' ``` ```rust use reqwest::{Client, StatusCode}; use serde::{Deserialize, Serialize}; use serde_json::json; #[derive(Debug, Serialize, Deserialize)] struct SubscriptionResponse { subscription_id: String, } const LIGHT_CLIENT_URL: &str = "https://api.lightclient.mainnet.avail.so"; #[tokio::main] async fn main() { let client = Client::new(); let subscriptions_url = format!("{LIGHT_CLIENT_URL}/v2/subscriptions"); let topics = vec!["header-verified", "confidence-achieved", "data-verified"]; let data_fields = vec!["data", "extrinsic"]; let response = client.post(&subscriptions_url) .header("Content-Type", "application/json") .body(json!({ "topics": topics, "data_fields": data_fields }).to_string()) .send() .await .unwrap(); match response.status() { StatusCode::OK => { let subscription_response: SubscriptionResponse = response.json().await.unwrap(); println!("Subscription ID: {}", subscription_response.subscription_id); } _ => { eprintln!("Failed to create subscription: {}", response.status()); } } // ...error handling... } ```
Sample Response: ```yaml { "subscription_id": "{subscription-id}" } ```
### Initialize the Websocket connection You can use this method to actually connect to Avail light client web socket. Multiple connections are currently allowed. To connect to the Avail LC websocket API, you need: 1. Access to a [running Light Client](/docs/da/operate/run-a-light-client/light-client#running-the-light-client). 2. A subscription ID generated using the [`v2/subscriptions`](#v2subscriptions) method. 3. to run this wscat command in the terminal: #### Local ```sh wscat -c ws://127.0.0.1:7007/v2/ws/{subscription-id} ``` #### Remote ```sh wscat -c wss://api.lightclient.mainnet.avail.so/v2/ws/{subscription-id} ``` Your terminal should look something like this: Avail-fusion > **Note** > > Please note that you will regularly receive information related to the topics you chose to subscribe to > for as long as the `ws` connection persists, even if you don't actually send any messages. Every request should contain unique **request\_id** field, used to correlate request with response. ## Subscription IDs vs Request IDs Each time you use the [`v2/subscriptions`](#v2subscriptions) method, you will receive a unique **subscription\_id**. This ID is used to connect to the websocket server. Each of these IDs will be of the [UUID4 format](https://www.uuidgenerator.net/version4). Coming to requests, every request you make to the websocket server should contain a **request\_id** field, which will need to be a UUID4 value. You can choose to use a single, random UUID4 value to send all your requests, or you can use a unique UUID4 value for each request you send. The choice is yours. Using a single UUID4 value is simple, but using a unique UUID4 value for each request can help you correlate each response with a unique request. The Avail LC API was designed with dev experience in mind, and this way you can choose the way that suits you best. ### Fetch the latest block > **Note** > > **LOOKING FOR INSTRUCTIONS ON HOW TO RUN YOUR OWN LIGHT CLIENT?** > You can check out [our docs here](/docs/da/operate/run-a-light-client/light-client#running-the-light-client) for instructions on how to run your own light client. Gets the version of the light client binary, and the version of the Avail node it is connected to. *Params*: * None *Response*: * Light Client version * Network version #### CURL ```bash filename="CURL" curl "localhost:7007/v2/version" ``` #### Rust ```bash filename="CURL" curl "https://api.lightclient.mainnet.avail.so/v2/version" ``` ```rust use reqwest::StatusCode; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct VersionResponse { version: String, network_version: String, } const LIGHT_CLIENT_URL: &str = "https://api.lightclient.mainnet.avail.so"; #[tokio::main] async fn main() { let version_url = format!("{LIGHT_CLIENT_URL}/v2/version"); let response = reqwest::get(&version_url).await.unwrap(); if response.status() == StatusCode::OK { let response_text = response.text().await.unwrap(); println!("Raw response: {}", response_text); let version_info: VersionResponse = serde_json::from_str(&response_text).unwrap(); println!( "Light Client version: {}, Network version: {}", version_info.version, version_info.network_version ); } else { eprintln!("Failed to get version: {}", response.status()); } // ...error handling... } ```
Sample Response: ```json { "version":"v1.9.0", "network_version":"1.10" } ```
### Request current Avail light client status data > **Note** > > While the `SubscriptionID` generated by your Light Client is unique, and you need it to initially connect to the client, > you can use **ANY** [UUID4 number](https://www.uuidgenerator.net/version4) > as the `request_id` in your request. Request current Avail light client status data. *Sample Request:* #### json ```json {"type":"status","request_id":"4a482bb0-3c22-475d-a2b8-af1c27aa2636"} ``` *Sample Response:* ```json {"topic":"status","request_id":"4a482bb0-3c22-475d-a2b8-af1c27aa2636","message":{"modes":["light","app"],"app_id":13,"genesis_hash":"0xb91746b45e0346cc2f815a520b9c6cb4d5c0902af848db0a80f85932d2e8276a","network":"wss://avail-mainnet.public.blastapi.io/2.2.1-4f0439f4448/39","blocks":{"latest":828832,"available":{"first":828743,"last":828831},"app_data":{"first":828743,"last":828831}}}} ``` ### Submit data to Avail DA > **Note** > > While the `SubscriptionID` generated by your Light Client is unique, and you need it to initially connect to the client, > you can use **ANY** [UUID4 number](https://www.uuidgenerator.net/version4) > as the `request_id` in your request. *Sample Request:* #### json ```json {"type":"submit","request_id":"4a482bb0-3c22-475d-a2b8-af1c27aa2636","message":{"data":"dGVzdAo="}} ``` > **Note** > > **HOW TO SUBMIT DATA USING THE LIGHT CLIENT?** > > 1. To use this method you need to run your Light Client in the `app-client` mode. > You can then submit data directly to the `appID` you configured while booting up the Light Client. > > 2. You can only pass `Base64` encoded data to be submitted via the Light Client. > You can use [this website](https://www.base64encode.org/) to encode & decode your data into the required formats. *Sample Response:* ```json {"topic":"data-transaction-submitted","request_id":"4a482bb0-3c22-475d-a2b8-af1c27aa2636","message":{"block_number":597725,"block_hash":"0x84803b93bf96aea90fae8fcb21cae70d310783ae8e9c4f4e1d696cec2791c0e3","hash":"0x290efdc7856fd29ec406c610f79aaa3c8079c11f8338093efad739b454bef0ac","index":1}} ``` ### Request Avail light client version data > **Note** > > While the `SubscriptionID` generated by your Light Client is unique, and you need it to initially connect to the client, > you can use **ANY** [UUID4 number](https://www.uuidgenerator.net/version4) > as the `request_id` in your request. Request Avail light client version data. *Sample Request:* #### json ```json {"topic":"version","request_id":"4a482bb0-3c22-475d-a2b8-af1c27aa2636","message":{"version":"v1.12.4","network_version":"2.2.1-4f0439f4448"}} ``` *Sample Response:* ```json {"topic":"version","request_id":"4a482bb0-3c22-475d-a2b8-af1c27aa2636","message":{"version":"v1.7.10","network_version":"1.10"}} ``` ### Retrieve Pre-Image Data > **Note** > > **NEED AN API KEY?** > Contact our team to get an API key for accessing the Turbo DA API endpoints. > **Endpoint:** `GET /v1/get_pre_image` Retrieves the original data that was previously submitted to Turbo DA. ## Parameters * `x-api-key` - Your API authentication key (required) * `submission_id` - The unique identifier received when data was submitted (query parameter) ## Response * The raw binary data that was originally submitted #### CURL ```bash filename="Fetching raw data against your submission ID" curl -X GET 'https://staging.turbo-api.availproject.org/v1/get_pre_image?submission_id=YOUR_SUBMISSION_ID' \ -H 'x-api-key: YOUR_API_KEY' ```
Sample Response: ``` { "data": "Raw binary data" } ``` > If the submission ID is invalid, you'll receive an appropriate HTTP error code with an error message: ```json { "error": "Customer Expenditure entry not found" } ```
> **Note** > > This endpoint complements the `submit_raw_data` endpoint by allowing users to retrieve the original data they submitted using the submission ID they received. > It's particularly useful for verifying that data was correctly stored or for retrieving data that was submitted by others in your organization. ### Get Submission Information > **Note** > > **NEED AN API KEY?** > Contact our team to get an API key for accessing the Turbo DA API endpoints. > **Endpoint:** `GET /v1/get_submission_info` Retrieves metadata and status information about a previous data submission to Turbo DA. ## Parameters * `x-api-key` - Your API authentication key (required) * `submission_id` - The unique identifier received when data was submitted (query parameter) ## Response * Metadata about the submission including status, transaction details, and timestamps #### CURL ```bash filename="Fetching submission info against your submission ID" curl -X GET 'https://staging.turbo-api.availproject.org/v1/get_submission_info?submission_id=YOUR_SUBMISSION_ID' \ -H 'x-api-key: YOUR_API_KEY' ```
Sample Response: ```json { "data": { "amount_data": "20.00 B", "block_hash": "0x087c21csd7cdc3d08y007eb940b0883175a20a22965e61819d533efa8d601aec1", "block_number": 1465348, "created_at": "2023-06-15T10:30:45Z", "data_billed": "1024", "data_hash": "0xc30f0eadacfc1579a2a6cee3b3154bf5df8f41ac824d555e74363b6fc55df8f8", "fees": "124443109311818076", "tx_hash": "0xff57e96bee175118f8c3779241469170b692a3d91697182af92774e594963969", "tx_index": 1, "user_id": "user@example.com" }, "error": null, "id": "7b8f9e2a-c531-4d45-8c7a-1b2d3e4f5g6h", "state": "Finalized", } ``` > If the submission ID is invalid or not found, you'll receive an appropriate HTTP error code with an error message:
### Submit JSON Data to Turbo DA > **Note** > > **Why does this endpoint exist?** > > 1. The `submit_data` endpoint exists to provide a more structured interface for applications that prefer working with JSON. > > 2. For submitting files or arbitrary binary data, use the [`submit_raw_data`](/docs/da/api-reference/avail-turbo-da-api/submit-raw-data) endpoint instead. > **Note** > > **NEED AN API KEY?** > Contact our team to get an API key for accessing the Turbo DA API endpoints. > **Endpoint:** `POST /v1/submit_data` Submits string data in JSON format to Turbo DA. This endpoint is designed for applications that prefer working with structured JSON data rather than raw binary content. ## Parameters * `x-api-key` - Your API authentication key (required) * `Content-Type` - Must be `application/json` ## Request Body ```json { "data": "Your string data here" } ``` ## Response * **submission\_id** - Unique identifier for tracking your submission #### CURL ```bash filename="Submitting JSON data" curl -X POST 'https://staging.turbo-api.availproject.org/v1/submit_data' \ -H 'x-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"data": "Hello Avail Network!"}' ```
Sample Response: ```json { "submission_id": "" } ``` > If the request fails due to invalid API key or server error, you'll receive an appropriate HTTP error code with an error message: ```json { "error": "Error message details" } ```
### Submit Raw Data to Turbo DA > **Note** > > **NEED AN API KEY?** > Contact our team to get an API key for accessing the Turbo DA API endpoints. > **Endpoint:** `POST /v1/submit_raw_data` Submits raw data to Turbo DA. ## Parameters * `x-api-key` - Your API authentication key (required) * `Content-Type` - Must be `application/octet-stream` ## Response * **submission\_id** - Unique identifier for tracking your submission #### Submitting a file ```bash filename="Submitting a file" # Create a sample file echo "This is test data for Avail network" > data.txt # Submit the file curl -X POST 'https://staging.turbo-api.availproject.org/v1/submit_raw_data' \ -H 'x-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/octet-stream' \ --data-binary '@data.txt' ``` #### Submitting raw data ```bash filename="Submitting raw data" curl -X POST 'https://staging.turbo-api.availproject.org/v1/submit_raw_data' \ -H 'x-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/octet-stream' \ --data-binary 'Hello Avail Network!' ```
Sample Response: ````json { "submission_id": "" } > If the request fails due to invalid API key or server error, you'll receive an appropriate HTTP error code with an error message: ```json { "error": "Error message details" } ````
### author-submit-and-watch-extrinsic > **Error** > > **`author_submitAndWatchExtrinsic` IS NOT RECOMMENDED FOR USE RIGHT NOW** > > 1. Avail builds on top of the [Polkadot SDK](https://docs.polkadot.com/develop/parachains/intro-polkadot-sdk/#substrate) (formerly known as Substrate) > and implements most of it's underlying calls and extrinsics. > 2. The `author_submitAndWatchExtrinsic` RPC call is known to be buggy and unreliable, and as such, not recommended for use. > 3. We recommend most devs [use our dedicated SDKs](/docs/da/api-reference/avail-node-api) instead of trying to use this RPC call directly. > 4. You can read more about the problem in this Github issue: [https://github.com/paritytech/subxt/issues/1668](https://github.com/paritytech/subxt/issues/1668) > 5. Since the problem is upstream, we can't fix it directly. > 6. We will keep this page updated with any new information :) ### author-submit-extrinsic > **Note** > > **WE RECOMMEND USING THE AVAIL SDKs DIRECTLY** > > 1. The `author_submitExtrinsic` RPC call is a low-level API that allows you to manually submit any extrinsic to the Avail network using a signed hash. > 2. We recommend using our dedicated SDKs instead of using this RPC call directly for convenience. > 3. The SDKs themselves use this RPC call internally, and offer a higher level of abstraction for interacting with the network. > **Note** > > **KNOW THE DIFFERENCE** > > 1. `author_submitExtrinsic` & `author_submitAndWatchExtrinsic` are different RPC calls that serve different, but similar purposes. > 2. We recommend not using the latter directly either. You can read about the problems with it [in this page in our docs](/docs/da/api-reference/avail-node-api/author-submit-and-watch-extrinsic). ### Transfer all funds from one account to another On-chain name of extrinsic: `balances_transferAll` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ------------------------------------------------ | | dest | string | false | account that will receive funds | | keepAlive | boolean | false | if set to false it will reap the account as well | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ------------------------------------------------ | | dest | \&str | false | account that will receive funds | | keepAlive | bool | false | if set to false it will reap the account as well | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------ | | api | API | false | api for avail chain | | dest | string | false | account that will receive funds | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Return value On failure, a reason of failure is returned. On Success, TransferEvent event, KilledAccount (optionally) event, transaction hash and block hash is returned. ## Minimal Example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK } from 'avail-js-sdk'; dotenv.config(); export async function transferAll() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Sender Address: ", account.address); // Destination address to send all available AVAIL to const destinationAddress = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log("Recipient Address: ", destinationAddress); // Setting this value to false will reap your account const keepAlive = true; // Create transfer all transaction const tx = sdk.tx.balances.transferAll(destinationAddress, keepAlive); console.log("Submitting transfer all transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); console.log("Transfer completed successfully"); process.exit(0); } // Execute the function transferAll(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn transfer_all() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Executing the transaction let dest = AccountId::from_str("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk").unwrap(); // Please take note of the `keep_alive` bool parameter // If set to true (which is the case right now), the transfer transaction will leave the origin account with a small balance // that is above the existential deposit and prevents the account from being reaped // Set the `keep_alive` parameter to `false` only if you are ok with the origin account being reaped let tx = sdk.tx.balances.transfer_all(dest, true); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } // Add a main function to call transfer_all #[tokio::main] async fn main() { if let Err(e) = transfer_all().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Convert the hex string to a MultiAddress destAddress, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } dest := destAddress.ToMultiAddress() // Set to false if you don't want to keep the account alive keepAlive := true // Transferring all funds tx := sdk.Tx.Balances.TransferAll(dest, keepAlive) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Transfer funds without ensuring min balance for sender On-chain name of extrinsic: `balances_transferAllowDeath` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | dest | string | false | account that will receive funds | | value | BN | false | amount that is send. 10^18 is equal to 1 AVL | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | dest | string | false | account that will receive funds | | value | BN | false | amount that is send. 10^18 is equal to 1 AVAIL | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------ | | api | API | false | api for avail chain | | dest | string | false | account that will receive funds | | amount | Ucompact | false | amount that is send. 10^18 is equal to 1 AVL | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Return value On failure, a reason of failure is returned. On Success, TransferEvent event, KilledAccount (optionally) event, transaction hash and block hash is returned. ## Minimal Example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, BN } from 'avail-js-sdk'; dotenv.config(); export async function transferAllowDeath() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Sender Address: ", account.address); // Destination address to send AVAIL to const destinationAddress = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log("Recipient Address: ", destinationAddress); // Amount to transfer: 12.345 AVAIL const amount = new BN('12345000000000000000'); // Create transfer transaction const tx = sdk.tx.balances.transferAllowDeath(destinationAddress, amount); console.log("Submitting transfer transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); console.log("Transfer completed successfully"); process.exit(0); } // Execute the function transferAllowDeath(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn transfer_allow_death() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Executing the transaction let dest = AccountId::from_str("5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw").unwrap(); let amount = 12_345_000_000_000_000_000u128; // 12.345 AVAIL being transferred to the destination account let tx = sdk.tx.balances.transfer_allow_death(dest, amount); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); println!("Transfer completed successfully"); Ok(()) } // Add a main function to call transfer_allow_death #[tokio::main] async fn main() { if let Err(e) = transfer_allow_death().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Destination address destAddress, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } dest := destAddress.ToMultiAddress() // Create a Balance from a string // The value is 10 AVAIL amount, err := metadata.NewBalanceFromString("10000000000000000000") if err != nil { log.Fatalf("Failed to create balance: %v", err) } // Transferring funds without the // necessary checks of keeping the sender's account alive tx := sdk.Tx.Balances.TransferAllowDeath(dest, amount) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) fmt.Println("Transfer completed successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Transfer funds while ensuring min balance for sender On-chain name of extrinsic: `balances_transferKeepAlive` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | dest | string | false | account that will receive funds | | value | BN | false | amount that is send. 10^18 is equal to 1 AVL | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | dest | \&str | false | account that will receive funds | | value | u128 | false | amount that is send. 10^18 is equal to 1 AVAIL | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------ | | api | API | false | api for avail chain | | dest | string | false | account that will receive funds | | amount | Ucompact | false | amount that is send. 10^18 is equal to 1 AVL | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Return value On failure, a reason of failure is returned. On Success, TransferEvent event, transaction hash and block hash is returned. ## Basic Example #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, BN } from 'avail-js-sdk'; dotenv.config(); export async function transferKeepAlive() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Sender Address: ", account.address); // Destination address to send AVAIL to const destinationAddress = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log("Recipient Address: ", destinationAddress); // Amount to transfer: 12 AVAIL const amount = new BN('12000000000000000000'); // 12 with 18 zeroes console.log("Transfer Amount: 12 AVAIL"); // Create transfer transaction const tx = sdk.tx.balances.transferKeepAlive(destinationAddress, amount); console.log("Submitting transfer transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); console.log("Transfer completed successfully"); process.exit(0); } // Execute the function transferKeepAlive(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn transfer_keep_alive() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Executing the transaction let dest = AccountId::from_str("5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw").unwrap(); let amount = 1_000_000_000_000_000_000u128; // 1 AVAIL being transferred to the destination account let tx = sdk.tx.balances.transfer_keep_alive(dest, amount); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); println!("Transfer completed successfully"); Ok(()) } // Add a main function to call transfer_keep_alive #[tokio::main] async fn main() { if let Err(e) = transfer_keep_alive().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Destination address destAddress, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } dest := destAddress.ToMultiAddress() // Create a Balance from a string // The value is 10 AVAIL amount, err := metadata.NewBalanceFromString("10000000000000000000") if err != nil { log.Fatalf("Failed to create balance: %v", err) } // Transferring funds while ensuring the sender's account // retains a minimum balance tx := sdk.Tx.Balances.TransferKeepAlive(dest, amount) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) fmt.Println("Transfer completed successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" name="cmd7" > go mod tidy > ``` > > and try again. ### Fetch block data from Avail DA using RPC calls The Avail node supports a variety of RPC calls for fetching block data. This page covers a few different calls that are commonly used to fetch block data: ## Fetch block hash using block number ### Parameters #### avail-js | parameter | type | optional | description | | ----------- | ------ | -------- | ------------------------------------------------------------------------------------- | | blockNumber | number | true | The block number of the block to fetch (fetches hash of latest block if not provided) | #### avail-rust | parameter | type | optional | description | | ----------- | ------ | -------- | ------------------------------------------------------------------------------------- | | blockNumber | number | true | The block number of the block to fetch (fetches hash of latest block if not provided) | #### avail-go | parameter | type | optional | description | | ----------- | ------ | -------- | ------------------------------------------------------------------------------------- | | blockNumber | number | true | The block number of the block to fetch (fetches hash of latest block if not provided) | ### Example #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import { SDK } from "avail-js-sdk"; export async function chainGetBlockHash() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // 1. Gets the block hash for the latest block if no argument is provided // 2. Gets the block hash for the block at the given block number if a block number is provided const hash = await sdk.client.api.rpc.chain.getBlockHash(1451847) console.log("getBlockHash") console.log(hash.toJSON()) process.exit(0); } // Execute the function chainGetBlockHash() ``` 2. Run the script using the following command: ```bash filename="terminal" node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; pub async fn get_block_hash() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // 1. Get the block hash for a specific block if argument is provided // 2. Get the latest block hash if no argument is provided let block_hash = rpc::chain::get_block_hash(&sdk.client, Some(1451847)).await?; println!("Latest Block Hash: {:?}", block_hash); Ok(()) } #[tokio::main] async fn main() -> Result<(), ClientError> { get_block_hash().await?; Ok(()) } ``` 2. Run the script using the following command: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" prim "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash by not passing any parameters latestBlockHash, err := sdk.Client.Rpc.Chain.GetBlockHash(prim.None[uint32]()) if err != nil { log.Fatalf("Failed to get the leatest block hash: %v", err) } // Print the block hash fmt.Println("Latest Block Hash: ", latestBlockHash) // Get a specific block hash by passing the block number specificBlockHash, err := sdk.Client.Rpc.Chain.GetBlockHash(prim.Some[uint32](1451847)) if err != nil { log.Fatalf("Failed to get the specific block hash: %v", err) } // Print the block hash fmt.Println("Specific Block Hash: ", specificBlockHash) } ``` 2. Run the script using the following command: ```bash filename="terminal" name="cmd6" go run main.go ``` ## Fetch block header using block hash ### Parameters #### avail-js | parameter | type | optional | description | | --------- | ------ | -------- | ------------------------------------------------------------------------------- | | blockHash | string | true | The hash of the block to fetch (fetches header of latest block if not provided) | #### avail-rust | parameter | type | optional | description | | --------- | ------ | -------- | ------------------------------------------------------------------------------- | | blockHash | string | true | The hash of the block to fetch (fetches header of latest block if not provided) | #### avail-go | parameter | type | optional | description | | --------- | ------ | -------- | ------------------------------------------------------------------------------- | | blockHash | string | true | The hash of the block to fetch (fetches header of latest block if not provided) | ### Example #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import { SDK } from "avail-js-sdk"; export async function chainGetBlockHeader() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // 1. Gets the block header for the latest block if no argument is provided // 2. Gets the block header for a specific block if a block hash is provided const header = await sdk.client.api.rpc.chain.getHeader("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1") console.log("getBlockHeader") console.log(header.toJSON()) process.exit(0); } // Execute the function chainGetBlockHeader() ``` 2. Run the script using the following command: ```bash filename="terminal" node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; pub async fn get_block_header() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // 1. Gets the block header for a specific block if argument is provided // 2. Gets the latest block header if no argument is provided let block_hash = new_h256_from_hex("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1")?; // Get the latest block header let latest_block_header = rpc::chain::get_header(&sdk.client, None).await?; // Get the block header for a specific block let block_header = rpc::chain::get_header(&sdk.client, Some(block_hash)).await?; println!("Latest Block Header: {:?}", latest_block_header); println!("Block Header: {:?}", block_header); Ok(()) } #[tokio::main] async fn main() -> Result<(), ClientError> { get_block_header().await?; Ok(()) } ``` 2. Run the script using the following command: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" prim "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash by not passing any parameters latestBlockHeader, err := sdk.Client.Rpc.Chain.GetHeader(prim.None[prim.H256]()) if err != nil { log.Fatalf("Failed to get the latest block header: %v", err) } // Print the block header fmt.Println("Latest Block Header: ", latestBlockHeader) // Get a specific block header by passing the block hash blockHash, err := prim.NewH256FromHexString("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1") if err != nil { log.Fatalf("Failed to create H256 from hex: %v", err) } specificBlockHeader, err := sdk.Client.Rpc.Chain.GetHeader(prim.Some[prim.H256](blockHash)) if err != nil { log.Fatalf("Failed to get the specific block header: %v", err) } // Print the block header fmt.Println("Specific Block Header: ", specificBlockHeader) } ``` 2. Run the script using the following command: ```bash filename="terminal" name="cmd6" go run main.go ``` ## Fetch entire block using block hash ### Parameters #### avail-js | parameter | type | optional | description | | --------- | ------ | -------- | ------------------------------------------------------------------------------ | | blockHash | string | true | The hash of the block to fetch (fetches block of latest block if not provided) | #### avail-rust | parameter | type | optional | description | | --------- | ------ | -------- | ------------------------------------------------------------------------------ | | blockHash | string | true | The hash of the block to fetch (fetches block of latest block if not provided) | #### avail-go | parameter | type | optional | description | | --------- | ------ | -------- | ------------------------------------------------------------------------------ | | blockHash | string | true | The hash of the block to fetch (fetches block of latest block if not provided) | ### Example #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import { SDK } from "avail-js-sdk"; export async function chainGetBlock() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // 1. Gets the block for the latest block if no argument is provided // 2. Gets block header and body for a specific block if a block hash is provided const block = await sdk.client.api.rpc.chain.getBlock("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1") console.log("getBlock") console.log(block.toJSON()) process.exit(0); } // Execute the function chainGetBlock() ``` 2. Run the script using the following command: ```bash filename="terminal" node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; pub async fn get_block() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // 1. Get the block for a specific block if argument is provided // 2. Get the latest block if no argument is provided let block_hash = new_h256_from_hex("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1")?; // Get the latest block let latest_block = rpc::chain::get_block(&sdk.client, None).await?; // Get the block for a specific block let specific_block = rpc::chain::get_block(&sdk.client, Some(block_hash)).await?; println!("Latest Block: {:?}", latest_block); // println!(" Specific Block: {:?}", block); Ok(()) } #[tokio::main] async fn main() -> Result<(), ClientError> { get_block().await?; Ok(()) } ``` 2. Run the script using the following command: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" prim "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block by not passing any parameters latestBlock, err := sdk.Client.Rpc.Chain.GetBlock(prim.None[prim.H256]()) if err != nil { log.Fatalf("Failed to get the latest block: %v", err) } // Print the block fmt.Println("Latest Block: ", latestBlock) // Get a specific block by passing the block hash blockHash, err := prim.NewH256FromHexString("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1") if err != nil { log.Fatalf("Failed to create H256 from hex: %v", err) } specificBlock, err := sdk.Client.Rpc.Chain.GetBlock(prim.Some(blockHash)) if err != nil { log.Fatalf("Failed to get the specific block: %v", err) } // Print the block fmt.Println("Specific Block: ", specificBlock) } ``` 2. Run the script using the following command: ```bash filename="terminal" name="cmd6" go run main.go ``` ### Fetch an AppID from Avail DA > **Note** > > `App Ids` are core to the dev experience on Avail DA, and we highly recommend you understand how they work before you start working with them. > You can check out [our docs for the same](/docs/da/build/interact/app-id). On-chain name of method: `dataAvailability_appKeys` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------ | -------- | ----------------------------------------------------- | | key | string | true | The `app_id` associated with this key will be fetched | #### avail-rust | parameter | type | optional | description | | --------- | ------ | -------- | ----------------------------------------------------- | | key | string | true | The `app_id` associated with this key will be fetched | #### avail-go | parameter | type | optional | description | | --------- | ------ | -------- | ----------------------------------------------------- | | key | string | true | The `app_id` associated with this key will be fetched | ## Return value On failure, a reason for failure is returned. On sucess, the returned JSON object contains: 1. `Owner`: The owner of the `app_id` 2. `appID`: The numerical index of the `app_id` ## Minimal example (Fetch a particular `app_id`) > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import { SDK, Pallets } from 'avail-js-sdk'; export async function getAppIdByKey() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Get the current block hash const blockHash = await sdk.client.bestBlockHash(); console.log(`Current block hash: ${blockHash}`); // Get storage at the current block const storageAt = await sdk.client.storageAt(blockHash); // The key to look up const appKey = "my Application Key Name!!!"; // Fetch the app keys entry for this key const entry = await Pallets.DataAvailabilityStorage.AppKeys.fetch(storageAt, appKey); if (entry === null) { console.log(`No app ID found for key: "${appKey}"`); } else { console.log(`App ID: ${entry.value.appId}`); console.log(`Owner: ${entry.value.owner.toSS58()}`); console.log(`Key: ${appKey}`); console.log("App Key fetched successfully"); } process.exit(0); } // Execute the function getAppIdByKey(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; use avail::data_availability::storage::types::app_keys::Param0; pub async fn da_app_keys() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let key = String::from("My Application Key").as_bytes().to_vec(); let key = Param0 { 0: key }; let block_hash = sdk.client.best_block_hash().await?; let storage = sdk.client.storage().at(block_hash); let address = avail::storage().data_availability().app_keys(key); let result = storage.fetch(&address).await?; dbg!(result); Ok(()) } // Add a main function to call da_app_keys #[tokio::main] async fn main() { if let Err(e) = da_app_keys().await { eprintln!("Error: {:?}", e); } else { println!("App Key fetched successfully"); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```json result = Some( AppKeyInfo { owner: AccountId32( [ 10, 255, 21, 20, 123, 225, 34, 49, 109, 40, 40, 86, 26, 184, 109, 251, 201, 136, 224, 246, 137, 212, 142, 149, 160, 242, 197, 86, 117, 80, 45, 110, ], ), id: AppId( 1, ), }, ) ```
> **Note** > > The list of numbers seperated by commas is merely a different way of representing the Substrate > addresses in the `AccountId32` format. #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" daPallet "github.com/availproject/avail-go-sdk/metadata/pallets/data_availability" prim "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash latestBlockHash, err := sdk.Client.BestBlockHash() if err != nil { log.Fatalf("Failed to get latest block hash: %v", err) } // Initialize the block storage blockStorage, err := sdk.Client.StorageAt(prim.Some(latestBlockHash)) if err != nil { log.Fatalf("Failed to get block storage: %v", err) } { storage := daPallet.StorageAppKeys{} keyString := "Citizen Justice" key := []byte(keyString) val, err := storage.Fetch(&blockStorage, key) if err != nil { log.Fatalf("Failed to fetch app keys: %v", err) } if val.IsSome() { entry := val.Unwrap() fmt.Println("App Key Owner: ", entry.Value.Owner.ToHuman()) fmt.Println("App Key AppId: ", entry.Value.AppId) fmt.Println("App Key fetched successfully") } else { fmt.Println("No app keys found for the given key.") } } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` ## Another example (Fetch all available `app_ids` registered on Avail DA) > **Note** > > 1. Think of the `dataAvailability_appKeys` as a method that returns all the `app_ids` registered on Avail DA > as a mapping of their names to their owner and index. > 2. In most cases a dev will be interested in fetching only a particular `app_id` and not all of them. > 3. We are however including both scenarios here. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import { SDK, Pallets } from 'avail-js-sdk'; export async function getAllAppIds() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Get the current block hash const blockHash = await sdk.client.bestBlockHash(); console.log(`Current block hash: ${blockHash}`); // Get storage at the current block const storageAt = await sdk.client.storageAt(blockHash); // Fetch all app keys entries const entries = await Pallets.DataAvailabilityStorage.AppKeys.fetchAll(storageAt); console.log(`Total number of app IDs: ${entries.length}`); // Display all app IDs and their details entries.forEach((entry) => { console.log(` App ID: ${entry.value.appId}`); console.log(` Owner: ${entry.value.owner.toSS58()}`); let keyString = ""; try { keyString = new TextDecoder().decode(entry.key); console.log(` Key (as string): ${keyString}`); } catch (e) { console.log(` Key (hex): 0x${Buffer.from(entry.key).toString('hex')}`); } }); process.exit(0); } // Execute the function getAllAppIds(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; pub async fn da_app_keys_iter() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let block_hash = sdk.client.best_block_hash().await?; let storage = sdk.client.storage().at(block_hash); let address = avail::storage().data_availability().app_keys_iter(); let mut results = storage.iter(address).await?; while let Some(Ok(kv)) = results.next().await { let key = (&kv.key_bytes[49..]).to_vec(); let key = String::from_utf8(key).unwrap(); println!("Key: {:?}", key); println!("Value: {:?}", kv.value); } Ok(()) } // Add a main function to call da_app_keys_iter #[tokio::main] async fn main() { if let Err(e) = da_app_keys_iter().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" daPallet "github.com/availproject/avail-go-sdk/metadata/pallets/data_availability" prim "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash latestBlockHash, err := sdk.Client.BestBlockHash() if err != nil { log.Fatalf("Failed to get latest block hash: %v", err) } // Initialize the block storage blockStorage, err := sdk.Client.StorageAt(prim.Some(latestBlockHash)) if err != nil { log.Fatalf("Failed to get block storage: %v", err) } // Fetch all app keys { storage := daPallet.StorageAppKeys{} val, err := storage.FetchAll(&blockStorage) if err != nil { log.Fatalf("Failed to fetch all app keys: %v", err) } if len(val) == 0 { log.Println("No app keys found.") } else { for i := 0; i < len(val); i++ { fmt.Println("App Key Owner: ", val[i].Value.Owner.ToHuman()) fmt.Println("App Key AppId: ", val[i].Value.AppId) } } } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` ### Create a new App ID on Avail DA > **Note** > > `App Ids` are core to the dev experience on Avail DA, and we highly recommend you understand how they work before you start working with them. > You can check out [our docs for the same](/docs/da/build/interact/app-id). On-chain name of extrinsic: `dataAvailability_createApplicationKey` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | key | string | false | name of the application key | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust ### Parameters | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | key | Key | false | name of the application key | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------ | | api | API | false | api for avail chain | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | | data | string | false | name of the application key | ## Returns On failure, a reason of failure is returned. On Success, ApplicationKeyCreated event, transaction hash and block hash is returned. ## Minimal Example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function createApplicationKey() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Use a fixed key string const key = "my Application Key Name"; // Create application key transaction const tx = sdk.tx.dataAvailability.createApplicationKey(key); console.log("Submitting transaction to create application key..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } // Extract event data if (res.events === undefined) throw new Error("No events found"); const event = res.events.findFirst(Pallets.DataAvailabilityEvents.ApplicationKeyCreated); if (event === undefined) throw new Error("ApplicationKeyCreated event not found"); const appId = event.id; console.log(`Application created successfully:`); console.log(`Owner: ${event.owner}`); console.log(`Key: ${event.keyToString()}`); console.log(`App Id: ${appId}`); console.log(`Transaction Hash: ${res.txHash}`); process.exit(0); } // Execute the function createApplicationKey() ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; type ApplicationKeyCreatedEvent = avail::data_availability::events::ApplicationKeyCreated; pub async fn create_application_key() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Application Key Creation // Please note that if an application key with the same `key` already exists, the transaction will fail. let key = "My Application Key".as_bytes().to_vec(); let tx = sdk.tx.data_availability.create_application_key(key); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; assert_eq!(res.is_successful(), Some(true), "Transactions must be successful"); let events = res.events.as_ref().unwrap(); let event = events.find_first::().unwrap(); let Some(event) = event else { return Err("Failed to get Application Key Created Event".into()); }; let app_id = event.id.0; println!("Application Key Created"); println!("{}",app_id); Ok(()) } // Add a main function to call create_application_key #[tokio::main] async fn main() { if let Err(e) = create_application_key().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" daPallet "github.com/availproject/avail-go-sdk/metadata/pallets/data_availability" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Generate an application key // Please note that the transaction will fail if // an AppID with the same key already exists key := "My new application key" tx := sdk.Tx.DataAvailability.CreateApplicationKey([]byte(key)) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Application Key Created Successfully") // Printing out all the values of the event ApplicationKeyCreated events := res.Events.UnsafeUnwrap() eventMyb := SDK.EventFindFirst(events, daPallet.EventApplicationKeyCreated{}) event := eventMyb.UnsafeUnwrap().UnsafeUnwrap() appId := event.Id fmt.Println(fmt.Sprintf(`Owner: %v, Key: %v, AppId: %v`, event.Owner.ToHuman(), string(event.Key), appId)) fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) fmt.Println("Application Key Created") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" name="cmd7" > go mod tidy > ``` > > and try again. ### Fetch the next available App ID on Avail DA > **Note** > > `App Ids` are core to the dev experience on Avail DA, and we highly recommend you understand how they work before you start working with them. > You can check out [our docs for the same](/docs/da/build/interact/app-id). On-chain name of method: `dataAvailability_nextAppId` > **Note** > > `app_ids`, once registered, cannot be claimed by another dev. > You can use this method to fetch the next available `app_id` for your awesome rollup :) ## Parameters #### avail-js None #### avail-rust None #### avail-go None ## Returns * `app_id`: The next available App ID ## Minimal example (Fetch the next available `app_id`) > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import { SDK, Pallets } from 'avail-js-sdk'; export async function getNextAppId() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Get the current block hash const blockHash = await sdk.client.bestBlockHash(); console.log(`Current block hash: ${blockHash}`); // Get storage at the current block const storageAt = await sdk.client.storageAt(blockHash); // Fetch the next available app ID const nextAppId = await Pallets.DataAvailabilityStorage.NextAppId.fetch(storageAt); console.log(`Next available App ID is: ${nextAppId}`); console.log("App ID fetched successfully"); process.exit(0); } // Execute the function getNextAppId(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ```
Sample Response: ```json 99 ```
#### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; pub async fn da_next_app_id() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let block_hash = sdk.client.best_block_hash().await?; let storage = sdk.client.storage().at(block_hash); let address = avail::storage().data_availability().next_app_id(); let result = storage.fetch_or_default(&address).await?; println!("Next available App ID is: {:?}", result); Ok(()) } // Add a main function to call da_next_app_id #[tokio::main] async fn main() { if let Err(e) = da_next_app_id().await { eprintln!("Error: {:?}", e); } else { println!("App ID fetched successfully"); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```json Some( AppId( 99, ), ) ```
#### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" daPallet "github.com/availproject/avail-go-sdk/metadata/pallets/data_availability" prim "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash latestBlockHash, err := sdk.Client.BestBlockHash() if err != nil { log.Fatalf("Failed to get latest block hash: %v", err) } // Initialize the block storage blockStorage, err := sdk.Client.StorageAt(prim.Some(latestBlockHash)) if err != nil { log.Fatalf("Failed to get block storage: %v", err) } // Call the StorageNextAppId function storage := daPallet.StorageNextAppId{} nextAppId, err := storage.Fetch(&blockStorage) if err != nil { log.Fatalf("Failed to fetch next app ID: %v", err) } fmt.Printf("Next available App ID is: %v\n", nextAppId) fmt.Println("App ID fetched successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` ### Submit new data to Avail DA On-chain name of extrinsic: `dataAvailability_submitData` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | data | string | false | data to be submitted | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | key | Key | false | name of the application key | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | ------------- | -------- | ------------------------------------------------------ | | api | API | false | api for avail chain | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | | data | SignerOptions | true | data to be submitted | | AppID | SignerOptions | true | AppID in which the transaction needs to be signed | ## Returns On failure, a reason of failure is returned. On Success, DataSubmitted event, transaction data, transaction hash and block hash is returned. ## Submit data using a specific `app_id` > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. > **Note** > > **PLEASE NOTE** > > 1. You can submit data to Avail DA using a specific `app_id` that you created. If you don't know how, > read more [in our docs here](/docs/da/api-reference/avail-node-api/da-create-application-key). > > 2. You can submit data to **ANY** `app_id`, even if you didn't create it. This however does not contitute an > attack vector since the rollups building on top of Avail DA can always filter out DA submissions. #### avail-js 1. Inside `your-file-name.ts`, paste the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function submitData() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Replace with your own AppID const appId = 89; console.log(`Submitting data to App Id: ${appId}`); // Create data submission transaction const data = "My Data Submission"; const tx = sdk.tx.dataAvailability.submitData(data); console.log("Submitting transaction with data..."); // Execute and wait for inclusion with app_id const res = await tx.executeWaitForInclusion(account, { app_id: appId }); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } // Extract event data if (res.events === undefined) throw new Error("No events found"); // Transaction Details console.log( `Block Hash: ${res.blockHash}, Block Number: ${res.blockNumber}, Tx Hash: ${res.txHash}, Tx Index: ${res.txIndex}` ); // Find DataSubmitted event const event = res.events.findFirst(Pallets.DataAvailabilityEvents.DataSubmitted); if (event === undefined) throw new Error("DataSubmitted event not found"); console.log(`Data submitted successfully:`); console.log(`Who: ${event.who}`); console.log(`DataHash: ${event.dataHash}`); console.log("Data submission completed successfully"); process.exit(0); } // Execute the function submitData(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `src/main.rs`, paste the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; type DataSubmissionCall = avail::data_availability::calls::types::SubmitData; pub async fn submit_data() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Please note that the tx will fail if this application key does not exist let my_application_key = 1; // Data Submission let data = String::from("My Data").into_bytes(); let options = Options::new().app_id(my_application_key); let tx = sdk.tx.data_availability.submit_data(data); let res = tx.execute_and_watch_inclusion(&account, options).await?; assert_eq!(res.is_successful(), Some(true), "Transactions must be successful"); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); // Decoding let decoded = res.decode_as::().await?; let Some(decoded) = decoded else { return Err("Failed to get Data Submission Call data".into()); }; let data = to_ascii(decoded.data.0).unwrap(); println!("Call data: {:?}", data); println!("Data Submission finished correctly"); Ok(()) } // Add a main function to call submit_data #[tokio::main] async fn main() { if let Err(e) = submit_data().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, paste the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Submit data to Avail appId := uint32(89) tx := sdk.Tx.DataAvailability.SubmitData([]byte("Submitting some data using avail-go-sdk")) res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions().WithAppId(appId)) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) fmt.Println("Data submission completed successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" name="cmd7" > go mod tidy > ``` > > and try again. > This will lead to your data being submitted through a specific `app_id`, which you can verify by looking > up your transaction on the [Avail explorer](https://explorer.availproject.org/#/explorer). ### Create a new nomination pool On-chain name of method: `nominationPools_create` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | --------------------------------------------------- | | amount | BN | false | The amount of funds to delegate to the pool | | root | string | false | The account to set as \[`PoolRoles::root`] | | nominator | string | false | The account to set as the \[`PoolRoles::nominator`] | | bouncer | string | false | The account to set as the \[`PoolRoles::bouncer`] | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | --------------------------------------------------- | | amount | u128 | false | The amount of funds to delegate to the pool | | root | \&str | false | The account to set as \[`PoolRoles::root`] | | nominator | \&str | false | The account to set as the \[`PoolRoles::nominator`] | | bouncer | \&str | false | The account to set as the \[`PoolRoles::bouncer`] | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | #### avail-go | parameter | type | optional | description | | --------- | ----------- | -------- | --------------------------------------------------- | | amount | u128 | false | The amount of funds to delegate to the pool | | root | \&str | false | The account to set as \[`PoolRoles::root`] | | nominator | \&str | false | The account to set as the \[`PoolRoles::nominator`] | | bouncer | \&str | false | The account to set as the \[`PoolRoles::bouncer`] | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | ## Returns On failure, a reason for the failure is returned. On success, the function will return a object of type `PoolCreateTxSuccess`. This object contains the details of the transaction and your newly created nomination pool. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. > **Warning** > > 1. The minimum amount of `AVAIL` required to create a nomination pool is `10_000 AVAIL`. > 2. You need to allocate privileges to some accounts while creating the pool. > >
> > Different roles within a nomination pool > > > A pool consists of 4 roles, each of which having different responsibilities in managing the running of the pool. > > 1. Root: Can change the nominator, bouncer, or itself. Further, it can perform any of the actions the nominator or bouncer can. > 2. Depositor: Creates the pool and is the initial member. The depositor can only leave the pool once all other members have left. Once they leave by withdrawing, the pool is fully removed from the system. > 3. Nominator: Can select the validators the pool nominates. > 4. Bouncer: Can change the pool's state and kick (permissionlessly unbond/withdraw) members if the pool is blocked. >
#### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, BN, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function nominationPoolsCreate() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Initial deposit amount: 10,000 AVAIL const amount = new BN(10).pow(new BN(18)).mul(new BN(10000)); // 10,000 AVAIL console.log("Initial Deposit: 10,000 AVAIL"); // Pool roles - using Alice's address for all roles const root = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; // Alice const nominator = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; // Alice const bouncer = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; // Alice console.log("Pool Roles:"); console.log(`Root: ${root}`); console.log(`Nominator: ${nominator}`); console.log(`Bouncer: ${bouncer}`); // Create pool transaction const tx = sdk.tx.nominationPools.create(amount, root, nominator, bouncer); console.log("Submitting create pool transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("\nPool creation completed successfully"); // Log all transaction details console.log("\nTransaction Details:"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); process.exit(0); } // Execute the function nominationPoolsCreate(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ```
Sample Response: ```js { "isErr": false, "event": { "depositor": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "poolId": "1" }, "event2": { "member": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "poolId": "1", "bonded": "10000", "joined": "true" }, "event": { "key": "0x4d79417765736f6d654b6579", "owner": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "id": "10" }, "events": [...], "txHash": "0x5ae9edbd2a2da96eeffc14cf9050d711082890fa6bfb8749ad2c4947565f3bd2", "txIndex": 1, "blockHash": "0x152338c1b0696d12664cf3d4c159af3d54beca151ba1ea8b00989a66dc8050b0", "blockNumber": 1 } ```
#### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn nomination_pools_create() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Setting the amount to bond and the pool id let amount = 10_000_000_000_000_000_000_000u128; // 10_000 Avail tokens //Setting the root, nominator and bouncer let root = account.public_key().to_account_id(); //Setting the root to be the account itself let nominator = AccountId::from_str("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk").unwrap(); let bouncer = AccountId::from_str("5D7LgWT5J6MVRa6PvTTXUfd9VvggEcguvPnnWAGK44CJKFEq").unwrap(); //Executing the transaction let tx = sdk.tx.nomination_pools.create(amount, root, nominator, bouncer); let res = tx.execute_and_watch_inclusion(&account, Options::new()).await?; assert_eq!(res.is_successful(), Some(true)); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = nomination_pools_create().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```rust showLineNumbers filename="avail-rust" name="cmd3" PoolCreateTxSuccess { event: Created { depositor: AccountId32(...), pool_id: 1, }, event2: Bonded { member: AccountId32(...), pool_id: 1, bonded: 1000000000000000000000000, joined: true, }, events: ExtrinsicEvents { ext_hash: 0xd68cd496c042b1de9484c03160dcaea0b66d939a7293d457b721e908542ce4dd, idx: 1, events: Events { event_bytes: [...], start_idx: 1, num_events: 19, }, }, tx_hash: 0xd68cd496c042b1de9484c03160dcaea0b66d939a7293d457b721e908542ce4dd, tx_index: 1, block_hash: 0x21119a080adf597abb22db237f8824a0dbd823feb6a809e2f2d9bb7872377e9d, block_number: 1, } ```
#### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Set the amount and addresses amount, err := metadata.NewBalanceFromString("1000000000000000000000000") // Example amount if err != nil { log.Fatalf("Failed to create balance: %v", err) } rootAddress, err := primitives.NewAccountIdFromAddress("5DqMavSQikX9eMzwHKiC8xS6VWB2yCd5gGQuQq7KheM2Mgc7") if err != nil { log.Fatalf("Failed to convert root address: %v", err) } nominatorAddress, err := primitives.NewAccountIdFromAddress("5FphMk7DhSdq7jXsQCVQthw7XTiCWxdA9ZS6V43rKeJzvya9") if err != nil { log.Fatalf("Failed to convert nominator address: %v", err) } bouncerAddress, err := primitives.NewAccountIdFromAddress("5G9fM7DhSdq7jXsQCVQthw7XTiCWxdA9ZS6V43rKeJzvya9") if err != nil { log.Fatalf("Failed to convert bouncer address: %v", err) } // Convert addresses to MultiAddress root := rootAddress.ToMultiAddress() nominator := nominatorAddress.ToMultiAddress() bouncer := bouncerAddress.ToMultiAddress() // Create the Create transaction tx := sdk.Tx.NominationPools.Create(amount, root, nominator, bouncer) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Create transaction successful") fmt.Printf("Block Hash: %v, Block Number: %v, Tx Hash: %v, Tx Index: %v\n", res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` ### Create a new nomination pool with a specific pool ID On-chain name of method: `nominationPools_createWithPoolId` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | --------------------------------------------------- | | amount | BN | false | The amount of funds to delegate to the pool | | root | string | false | The account to set as \[`PoolRoles::root`] | | nominator | string | false | The account to set as the \[`PoolRoles::nominator`] | | bouncer | string | false | The account to set as the \[`PoolRoles::bouncer`] | | poolId | number | false | pool id | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | --------------------------------------------------- | | amount | u128 | false | The amount of funds to delegate to the pool | | root | \&str | false | The account to set as \[`PoolRoles::root`] | | nominator | \&str | false | The account to set as the \[`PoolRoles::nominator`] | | bouncer | \&str | false | The account to set as the \[`PoolRoles::bouncer`] | | pool id | u32 | false | pool id | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | #### avail-go | parameter | type | optional | description | | --------- | ----------- | -------- | --------------------------------------------------- | | amount | u128 | false | The amount of funds to delegate to the pool | | root | \&str | false | The account to set as \[`PoolRoles::root`] | | nominator | \&str | false | The account to set as the \[`PoolRoles::nominator`] | | bouncer | \&str | false | The account to set as the \[`PoolRoles::bouncer`] | | pool id | u32 | false | pool id | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | ## Returns On failure, a reason for the failure is returned. On success, the function will return a object of type `PoolCreateWithPoolIdTxSuccess`. This object contains the details of the transaction and your newly created nomination pool. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. > **Warning** > > 1. The minimum amount of `AVAIL` required to create a nomination pool is `10_000 AVAIL`. > 2. You need to allocate privileges to some accounts while creating the pool. > >
> > Different roles within a nomination pool > > > A pool consists of 4 roles, each of which having different responsibilities in managing the running of the pool. > > 1. Root: Can change the nominator, bouncer, or itself. Further, it can perform any of the actions the nominator or bouncer can. > 2. Depositor: Creates the pool and is the initial member. The depositor can only leave the pool once all other members have left. Once they leave by withdrawing, the pool is fully removed from the system. > 3. Nominator: Can select the validators the pool nominates. > 4. Bouncer: Can change the pool's state and kick (permissionlessly unbond/withdraw) members if the pool is blocked. >
#### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, BN, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function nominationPoolsCreateWithPoolId() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Initial deposit amount: 10,000 AVAIL const amount = new BN(10).pow(new BN(18)).mul(new BN(10000)); // 10,000 AVAIL console.log("Initial Deposit: 10,000 AVAIL"); // Pool roles - using Alice's address for all roles const root = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; // Alice const nominator = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; // Alice const bouncer = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; // Alice const poolId = 0; // Specific pool ID to create // Create pool with ID transaction const tx = sdk.tx.nominationPools.createWithPoolId(amount, root, nominator, bouncer, poolId); console.log("Submitting create pool with ID transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("\nPool creation with ID completed successfully"); // Log all transaction details console.log("\nTransaction Details:"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); process.exit(0); } // Execute the function nominationPoolsCreateWithPoolId(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ```
Sample Response: ```js { "isErr": false, "event": { "depositor": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", "poolId": "0" }, "event2": { "member": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", "poolId": "0", "bonded": "10000", "joined": "true" }, "events": [...], "txHash": "0x6b50caed7950e67934cabbf88a1f7dc2e7e995ac608402f91a4db19be0da5c41", "txIndex": 1, "blockHash": "0xc06df7dbb1e404f54499f942479ddcffc92665c021ea07c2798fc2f354f403d3", "blockNumber": 6 } ```
#### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn nomination_pools_create_with_pool_id() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Setting the amount to bond and the pool id let amount = 10_000_000_000_000_000_000_000u128; // 10_000 Avail tokens let pool_id = 1; // You need to use a pool id that is not already in use //Setting the root, nominator and bouncer let root = account.public_key().to_account_id(); //Setting the root to be the account itself let nominator = AccountId::from_str("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk").unwrap(); let bouncer = AccountId::from_str("5D7LgWT5J6MVRa6PvTTXUfd9VvggEcguvPnnWAGK44CJKFEq").unwrap(); //Executing the transaction let tx = sdk.tx.nomination_pools.create_with_pool_id(amount, root, nominator, bouncer, pool_id); let res = tx.execute_and_watch_inclusion(&account, Options::new()).await?; assert_eq!(res.is_successful(), Some(true)); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = nomination_pools_create_with_pool_id().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```rust showLineNumbers filename="avail-rust" name="cmd3" PoolCreateWithPoolIdTxSuccess { event: Created { depositor: AccountId32(...), pool_id: 0, }, event2: Bonded { member: AccountId32(...), pool_id: 0, bonded: 1000000000000000000000000, joined: true, }, events: ExtrinsicEvents { ext_hash: 0xaa16bad7378608bda89476353a61c1ae1ecc36166f0c5adda50cd563162889db, idx: 1, events: Events { event_bytes: [], start_idx: 1, num_events: 19, }, }, tx_hash: 0xaa16bad7378608bda89476353a61c1ae1ecc36166f0c5adda50cd563162889db, tx_index: 1, block_hash: 0xc04789228e6fa209119336ac33bcd6280b6b0c22e5ef9125c36b9f4a04e58adc, block_number: 32, } ```
#### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Set the amount, pool ID, and addresses amount, err := metadata.NewBalanceFromString("1000000000000000000000000") // Example amount if err != nil { log.Fatalf("Failed to create balance: %v", err) } poolId := uint32(1) rootAddress, err := primitives.NewAccountIdFromAddress("5DqMavSQikX9eMzwHKiC8xS6VWB2yCd5gGQuQq7KheM2Mgc7") if err != nil { log.Fatalf("Failed to convert root address: %v", err) } nominatorAddress, err := primitives.NewAccountIdFromAddress("5FphMk7DhSdq7jXsQCVQthw7XTiCWxdA9ZS6V43rKeJzvya9") if err != nil { log.Fatalf("Failed to convert nominator address: %v", err) } bouncerAddress, err := primitives.NewAccountIdFromAddress("5G9fM7DhSdq7jXsQCVQthw7XTiCWxdA9ZS6V43rKeJzvya9") if err != nil { log.Fatalf("Failed to convert bouncer address: %v", err) } // Convert addresses to MultiAddress root := rootAddress.ToMultiAddress() nominator := nominatorAddress.ToMultiAddress() bouncer := bouncerAddress.ToMultiAddress() // Create the CreateWithPoolId transaction tx := sdk.Tx.NominationPools.CreateWithPoolId(amount, root, nominator, bouncer, poolId) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("CreateWithPoolId transaction successful") fmt.Printf("Block Hash: %v, Block Number: %v, Tx Hash: %v, Tx Index: %v\n", res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` ### Join a nomination pool On-chain name of method: `nominationPools_join` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | amount | BN | false | The amount of funds to delegate to the pool | | poolId | number | false | pool id | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | amount | u128 | false | The amount of funds to delegate to the pool | | pool id | u32 | false | pool id | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | #### avail-go | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | amount | u128 | false | The amount of funds to delegate to the pool | | pool id | u32 | false | pool id | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | ## Returns On failure, a reason for the failure is returned. On success, the function will return a object of type `PoolJoinTxSuccess`. This object contains the details of the transaction and some information about the nomination pool oyu just joined. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. > **Warning** > > 1. The minimum amount of `AVAIL` required to join a nomination pool is `100 AVAIL`. > 2. Enter the `poolId` carefully. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```javascript showLineNumbers filename="avail-js" import * as dotenv from 'dotenv'; import { Account, SDK, BN, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function nominationPoolsJoin() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Join amount: 1,000 AVAIL const amount = new BN(10).pow(new BN(18)).mul(new BN(1000)); // 1,000 AVAIL console.log("Join Amount: 1,000 AVAIL"); // Pool ID to join // Replace with the actual pool ID you want to join const poolId = 1; console.log(`Joining Pool ID: ${poolId}`); // Create join transaction const tx = sdk.tx.nominationPools.join(amount, poolId); console.log("Submitting join transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("Pool join operation completed successfully"); // Log all transaction details console.log("\nTransaction Details:"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); process.exit(0); } // Execute the function nominationPoolsJoin(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ```
Sample Response: ```js { "isErr": false, "event": { "member": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", "poolId": "1", "bonded": "10000", "joined": "true" }, "events": [...], "txHash": "0x06baecbb8680e90d025d1fd08044d0d251054a89e82dd460022bdf3796020050", "txIndex": 1, "blockHash": "0x82078130da46adacf5bdff86618ab6e1c443fda6d883d9fcf967a41a2e29d612", "blockNumber": 19 } ```
#### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; pub async fn nomination_pools_join() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Setting the amount to bond and the pool id let amount = 1_00_000_000_000_000_000_000_000u128; // 1_000_00 Avail tokens let pool_id = 1; //Executing the transaction let tx = sdk.tx.nomination_pools.join(amount, pool_id); let res = tx.execute_and_watch_inclusion(&account, Options::new()).await?; assert_eq!(res.is_successful(), Some(true)); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = nomination_pools_join().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```rust showLineNumbers filename="avail-rust" name="cmd3" PoolJoinTxSuccess { event: Bonded { member: AccountId32(...), pool_id: 1, bonded: 1000000000000000000000000, joined: true, }, events: ExtrinsicEvents { ext_hash: 0x1c3c2412859e9c1d29a17cdaad48ff835bfbc7bb1b2bda5686d152f7c5145a40, idx: 1, events: Events { event_bytes: [...], start_idx: 1, num_events: 12, }, }, tx_hash: 0x1c3c2412859e9c1d29a17cdaad48ff835bfbc7bb1b2bda5686d152f7c5145a40, tx_index: 1, block_hash: 0x67f28bfd6826522dc53ccfdec24dffbe9954ff4af8d96e81e983227af101786b, block_number: 24, } ```
#### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Set the amount to bond and the pool ID // 1_000_00 Avail tokens amount, err := metadata.NewBalanceFromString("1000000000000000000000000") if err != nil { log.Fatalf("Failed to create balance: %v", err) } poolId := uint32(1) // Create the join transaction tx := sdk.Tx.NominationPools.Join(amount, poolId) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Join transaction successful") fmt.Printf("Block Hash: %v, Block Number: %v, Tx Hash: %v, Tx Index: %v\n", res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` ### Nominate validator(s) for your nomination pool On-chain name of method: `nominationPools_nominate` ## Parameters #### avail-js | parameter | type | optional | description | | ---------- | ------------- | -------- | ----------------------------------------------- | | poolId | number | false | pool id | | validators | string\[] | false | list of validators to nominate | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | targets | &\[String] | false | list of validator addresses to nominate | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | #### avail-go | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | targets | &\[String] | false | list of validator addresses to nominate | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | Options | true | transaction parameters | ## Returns On failure, a reason for the failure is returned. On success, the function will return a object of type `NominateTxSuccess`. This object contains the details of the transaction and the nomination pool. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```javascript showLineNumbers filename="avail-js" import * as dotenv from 'dotenv'; import { Account, SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function nominationPoolsNominate() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Pool ID to nominate from const poolId = 1; console.log(`Pool ID: ${poolId}`); // Validator targets to nominate const validators = [ "5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY", // Alice Stash "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", // Bob ]; // Create nominate transaction const tx = sdk.tx.nominationPools.nominate(poolId, validators); console.log("Submitting pool nomination transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("\nPool nomination completed successfully"); // Log all transaction details console.log("\nTransaction Details:"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); process.exit(0); } // Execute the function nominationPoolsNominate(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ```
Sample Response: ```js { "isErr": false, "events": [...], "txHash": "0x98b993baf90183d85dece9357d3bc32311f4201b015b63845a13dbc22bf22370", "txIndex": 1, "blockHash": "0x84ef5a0ada4af71358ee701a2500bce7f6688efb554c32ba1a30c459f64d5370", "blockNumber": 48 } ```
#### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn nomination_pools_nominate() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Setting the pool id and the validators to nominate let pool_id = 1; // Use your pool id here //Setting an array of validators to nominate let validators = [ AccountId::from_str("5DqMavSQikX9eMzwHKiC8xS6VWB2yCd5gGQuQq7KheM2Mgc7").expect("Invalid account ID"), AccountId::from_str("5FphMk7DhSdq7jXsQCVQthw7XTiCWxdA9ZS6V43rKeJzvya9").expect("Invalid account ID"), ]; //Executing the transaction let tx = sdk.tx.nomination_pools.nominate(pool_id, validators.to_vec()); let res = tx.execute_and_watch_inclusion(&account, Options::new()).await?; assert_eq!(res.is_successful(), Some(true)); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = nomination_pools_nominate().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```rust showLineNumbers filename="avail-rust" name="cmd3" NominateTxSuccess { events: ExtrinsicEvents { ext_hash: 0x6e0ae6fde353974f8b46aace441c49ba7ab135fa3743e0e1331d35c4528dacfb, idx: 1, events: Events { event_bytes: [...], start_idx: 1, num_events: 8, }, }, tx_data: Nominate { targets: [ Id(AccountId32(...)), Id(AccountId32(...)), ], }, tx_hash: 0x6e0ae6fde353974f8b46aace441c49ba7ab135fa3743e0e1331d35c4528dacfb, tx_index: 1, block_hash: 0xd9b3c0e77d6b376b3963055f65156e30c63b4ecc54d6c113ecb431b9cf877bb8, block_number: 28, } ```
### Fetch information on the active era On-chain name of method: `staking_activeEra` ## Parameters #### avail-js None #### avail-rust None #### avail-go None ## Returns * `index`: The index of the active era * `start`: The timestamp when the active era started ## Minimal example (Fetch the active era) > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import { SDK, Pallets, BN } from "avail-js-sdk"; export async function getActiveEra() { // Initialize SDK with Turing endpoint const sdk = await SDK.New("wss://turing-rpc.avail.so/ws"); // Get the current block hash const blockHash = await sdk.client.bestBlockHash(); console.log(`Current block hash: ${blockHash}`); // Get storage at the current block const storageAt = await sdk.client.storageAt(blockHash); // Fetch active era information const activeEra = await Pallets.StakingStorage.ActiveEra.fetch(storageAt); if (!activeEra) { console.log("No active era found"); process.exit(1); } // Log all properties of activeEra console.log("\nAll Active Era Properties:"); for (const [key, value] of Object.entries(activeEra)) { console.log(`${key}: ${value}`); } process.exit(0); } // Execute the function getActiveEra(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; pub async fn staking_active_era() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let block_hash = sdk.client.best_block_hash().await?; let storage = sdk.client.storage().at(block_hash); let address = avail::storage().staking().active_era(); let result = storage.fetch(&address).await?; dbg!(result); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = staking_active_era().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```json result = Some( ActiveEraInfo { index: 174, start: Some( 1726523440000, ), }, ) ```
#### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" staPallet "github.com/availproject/avail-go-sdk/metadata/pallets/staking" prim "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash latestBlockHash, err := sdk.Client.BestBlockHash() if err != nil { log.Fatalf("Failed to get latest block hash: %v", err) } // Initialize the block storage blockStorage, err := sdk.Client.StorageAt(prim.Some(latestBlockHash)) if err != nil { log.Fatalf("Failed to get block storage: %v", err) } // Fetch the active era { storage := staPallet.StorageActiveEra{} val, err := storage.Fetch(&blockStorage) if err != nil { log.Fatalf("Failed to fetch active era: %v", err) } fmt.Println("Active Era: ", val.Unwrap()) } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` ### Bond AVAIL tokens on Avail DA On-chain name of extrinsic: `staking_bond` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------------------ | -------- | -------------------------------------------------------- | | value | BN | false | amount that is bond. 10^18 is equal to 1 AVL | | payee | StakingRewardDestination | false | Can be: "Stakzed", "Stash", "None" or an account address | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------------- | -------- | ------------------------------------------------------- | | value | u128 | false | amount that is bond. 10^18 is equal to 1 AVAIL | | payee | RewardDestination | false | Can be: "Staked", "Stash", "None" or an account address | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------- | | api | API | false | api for avail chain | | amount | Ucompact | false | amount that is bond. | | payee | Payee | false | Can be: "Staked", "Stash", "None" or an account address | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Returns On failure, a reason of failure is returned. On Success, Bonded event, transaction hash and block hash is returned. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, BN, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function stakingBond() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Bond amount: 10,000 AVAIL const value = new BN(10_000).mul(new BN(10).pow(new BN(18))); console.log("Bond Amount: 10,000 AVAIL"); // Reward destination const payee = "Staked"; console.log("Reward Destination: ", payee); // Create bond transaction const tx = sdk.tx.staking.bond(value, payee); console.log("Submitting bond transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("Bond completed successfully"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); process.exit(0); } // Execute the function stakingBond(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `src/main.rs`, paste the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::{ prelude::*, transactions::staking::RewardDestination, }; pub async fn staking_bond() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Setting amount of AVAIL to be staked let value = 1_000_000_000_000_000_000u128 * 1_000_000u128; // 1,000,000 AVAIL //Setting the payee to be a Validator let payee = RewardDestination::Staked; // Executing the transaction let tx = sdk.tx.staking.bond(value, payee); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; assert_eq!(res.is_successful(), Some(true)); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = staking_bond().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, paste the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Create a Balance from a string // The value here is 1000 AVAIL amount, err := metadata.NewBalanceFromString("1000000000000000000000") if err != nil { log.Fatalf("Failed to create balance: %v", err) } // Create a RewardDestination payee := metadata.RewardDestination{VariantIndex: 0} // Call the `Bond` function tx := sdk.Tx.Staking.Bond(amount, payee) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Stop validating on Avail DA On-chain name of extrinsic: `staking_chill` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------ | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | api | API | false | api for avail chain | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Returns On failure, a reason of failure is returned. On Success, Chilled event, transaction hash and block hash is returned. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function stakingChill() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Create chill transaction const tx = sdk.tx.staking.chill(); console.log("Submitting chill transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("Chill operation completed successfully"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); process.exit(0); } // Execute the function stakingChill(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `src/main.rs`, paste the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; pub async fn staking_chill() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Executing the transaction let tx = sdk.tx.staking.chill(); let res = tx.execute_and_watch_inclusion(&account, Options::new()).await?; assert_eq!(res.is_successful(), Some(true)); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = staking_chill().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, paste the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Create the chill transaction tx := sdk.Tx.Staking.Chill() // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Chill transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Nominate staked AVAIL tokens to one or more validators On-chain name of extrinsic: `staking_nominate` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | targets | string\[] | false | list of addresses to nominate | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ----------- | -------- | ----------------------------------------------- | | targets | &\[String] | false | list of addresses to nominate | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | --------- | -------- | ------------------------------------------------------ | | stash | string\[] | false | list od addresses to nominate | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | api | API | false | api for avail chain | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Returns On failure, a reason of failure is returned. On Success, Nominate transaction data, transaction hash and block hash is returned. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function stakingNominate() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Validator targets to nominate const targets = [ "5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY", // Alice Stash "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", // Bob ]; console.log("Nominating validators:"); targets.forEach((target, index) => { console.log(` ${index + 1}. ${target}`); }); // Create nominate transaction const tx = sdk.tx.staking.nominate(targets); console.log("Submitting nomination transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("Nomination completed successfully"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); process.exit(0); } // Execute the function stakingNominate(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `src/main.rs`, paste the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn staking_nominate() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Setting the Validator to be nominated, max 16 targets let targets = [ AccountId::from_str("5DqMavSQikX9eMzwHKiC8xS6VWB2yCd5gGQuQq7KheM2Mgc7").expect("Invalid account ID"), AccountId::from_str("5FphMk7DhSdq7jXsQCVQthw7XTiCWxdA9ZS6V43rKeJzvya9").expect("Invalid account ID"), ]; //Executing the transaction let tx = sdk.tx.staking.nominate(&targets); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; assert_eq!(res.is_successful(), Some(true)); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = staking_nominate().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, paste the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Convert the addresses to AccountId address1, err := primitives.NewAccountIdFromAddress("5DqMavSQikX9eMzwHKiC8xS6VWB2yCd5gGQuQq7KheM2Mgc7") if err != nil { log.Fatalf("Failed to convert address1: %v", err) } address2, err := primitives.NewAccountIdFromAddress("5FphMk7DhSdq7jXsQCVQthw7XTiCWxdA9ZS6V43rKeJzvya9") if err != nil { log.Fatalf("Failed to convert address2: %v", err) } // Create an array of AccountId targets := []primitives.MultiAddress{ address1.ToMultiAddress(), address2.ToMultiAddress(), } // Create the nominate transaction tx := sdk.Tx.Staking.Nominate(targets) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Nomination transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Unbond AVAIL tokens from Avail DA On-chain name of extrinsic: `staking_unbond` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | value | BN | false | amount of tokens to unbond | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | --------- | ------------- | -------- | ----------------------------------------------- | | value | u128 | false | amount of tokens to unbond | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------ | | amount | Ucompact | false | amount of tokens to unbond | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | api | API | false | api for avail chain | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Returns On failure, a reason of failure is returned. On Success, Unbonded event, transaction hash and block hash is returned. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, BN, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function stakingUnbond() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Unbond amount: 1 AVAIL const value = new BN(10).pow(new BN(18)); // 1 AVAIL console.log("Unbond Amount: 1 AVAIL"); // Create unbond transaction const tx = sdk.tx.staking.unbond(value); console.log("Submitting unbond transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("Unbond operation completed successfully"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); process.exit(0); } // Execute the function stakingUnbond(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `src/main.rs`, paste the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; pub async fn staking_unbond() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; let value = 1_000_000_000_000_000_000u128; // 1 AVAIL //Executing the transaction let tx = sdk.tx.staking.unbond(value); let res = tx.execute_and_watch_inclusion(&account, Options::new()).await?; assert_eq!(res.is_successful(), Some(true)); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = staking_unbond().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, paste the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Create a Balance from a string for the unbond amount unbondAmount, err := metadata.NewBalanceFromString("1000000000000000000") if err != nil { log.Fatalf("Failed to create balance: %v", err) } // Create the unbond transaction tx := sdk.Tx.Staking.Unbond(unbondAmount) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Unbond transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Become a validator on Avail DA On-chain name of extrinsic: `staking_validate` ## Parameters #### avail-js | parameter | type | optional | description | | ---------- | ------------- | -------- | ----------------------------------------------------- | | commission | number | false | how much validator charge nominators in 0 - 100 range | | blocked | boolean | false | whether or not this validator accepts nominations | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | | options | SignerOptions | true | used to overwrite existing signer options | #### avail-rust | parameter | type | optional | description | | ---------- | ----------- | -------- | ----------------------------------------------------- | | commission | u8 | false | how much validator charge nominators in 0 - 100 range | | blocked | bool | false | whether or not this validator accepts nominations | | waitFor | WaitFor | false | wait for block inclusion or finalization | | account | KeyringPair | false | account that will send and sign the transaction | #### avail-go | parameter | type | optional | description | | ---------------- | -------- | -------- | ------------------------------------------------------ | | commission | number | false | how much validator charge nominators in 0 - 100 range | | WaitForInclusion | WaitFor | false | wait for block inclusion or finalization | | api | API | false | api for avail chain | | Seed | Mnemonic | false | seed of the account that needs to sign the transaction | ## Returns On failure, a reason of failure is returned. On Success, ValidatorPrefsSet event, transaction hash and block hash is returned. ## Minimal example > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function stakingValidate() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Validator settings const commission = 5; // 5% const blocked = false; console.log(`Commission: ${commission}%`); console.log(`Blocked: ${blocked}`); // Create validate transaction const tx = sdk.tx.staking.validate(commission, blocked); console.log("Submitting validate transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("Validation setup completed successfully"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); process.exit(0); } // Execute the function stakingValidate(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `src/main.rs`, paste the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::transactions::staking::Commission; use avail_rust::prelude::*; pub async fn staking_validate() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; //Setting your Validator's commission and blocking status let commission = Commission::new(5)?; // 5% let blocked = false; // Not blocked //Executing the transaction let tx = sdk.tx.staking.validate(commission, blocked); let res = tx.execute_and_watch_inclusion(&account, Options::new()).await?; assert_eq!(res.is_successful(), Some(true)); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = staking_validate().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, paste the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Set validator preferences prefs := metadata.ValidatorPrefs{ Commission: metadata.NewPerbillFromU8(5), // 5% commission Blocked: false, // Not blocked } // Create the validate transaction tx := sdk.Tx.Staking.Validate(prefs) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Validation transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Fetch balances and other information for an account On-chain name of method: `system_account` ## Parameters #### avail-js | parameter | type | optional | description | | --------- | ---- | -------- | --------------------------------------------- | | address | SS58 | true | The account address to fetch information for | #### avail-rust | parameter | type | optional | description | | --------- | ---- | -------- | --------------------------------------------- | | address | SS58 | true | The account address to fetch information for | #### avail-go | parameter | type | optional | description | | --------- | ---- | -------- | --------------------------------------------- | | address | SS58 | true | The account address to fetch information for | ## Returns * `nonce`: Current nonce of the account on Avail DA * `consumers`: The number of other modules that currently depend on this account's existence. The account cannot be reaped until this is zero * `providers`: The number of other modules that allow this account to exist. The account may not be reaped until this is zero. * `sufficients`: The number of modules that allow this account to exist for their own purposes only. The account may not be reaped until this is zero. * `free`: Amount of Transferrable AVAIL tokens with the account * `reserved`: Amount of AVAIL tokens that are not bonded, but also not yet freely available * `frozen`: Amount of AVAIL tokens currently staked by the account * `flags`: Some extra information about the account > **Note** > > **NONCE** > > * Every account on Avail DA starts with a nonce value of `0`. This number represents > the number of transactions executed on Avail DA by that particular account. > > * Every successive transaction will have a nonce value that is incremented by `1` from the previous transaction. > > * To extend this a bit further, the sum of all non-zero nonces on Avail DA will be equal to the total number of transactions executed on Avail DA. ## Minimal example (Fetch account information for a single account) > **Note** > > 1. You will need to set up the dev environment required to run this example. > For instructions, [check out our docs here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). > > 2. If you're sending an extrinsic (i.e conducting a transaction) you will need to replace the demo seed phrase with your own seed phrase. > The rest of the code should work as is. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function getAccountBalance() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Address to check balance for const address = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log(`Checking balance for address: ${address}`); // Get the current block hash const blockHash = await sdk.client.bestBlockHash(); // Get storage at the current block const storageAt = await sdk.client.storageAt(blockHash); // Fetch account information const accountInfo = await Pallets.SystemStorage.Account.fetch(storageAt, address); // Format balances in AVAIL (dividing by 10^18) const free = accountInfo.value.accountData.free.toString(); const reserved = accountInfo.value.accountData.reserved.toString(); const frozen = accountInfo.value.accountData.frozen.toString(); console.log("The following balances are in the smallest units, divide by 10^18 to get the balance in AVAIL"); console.log(`Free Balance: ${free}`); console.log(`Reserved Balance: ${reserved}`); console.log(`Frozen Balance: ${frozen}`); console.log("Account information fetched successfully"); process.exit(0); } // Execute the function getAccountBalance(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; use core::str::FromStr; pub async fn system_account() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let account_id = AccountId::from_str("5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg").unwrap(); let block_hash = sdk.client.best_block_hash().await?; let storage = sdk.client.storage().at(block_hash); let address = avail::storage().system().account(account_id); let result = storage.fetch(&address).await?; if let Some(account) = result { println!("Consumers: {}", account.consumers); println!("Data: {:?}", account.data); println!("Nonce: {}", account.nonce); println!("Providers: {}", account.providers); println!("Sufficients: {}", account.sufficients); } Ok(()) } // Add a main function to call system_account #[tokio::main] async fn main() { if let Err(e) = system_account().await { eprintln!("Error: {:?}", e); } else { println!("Account information fetched successfully"); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ```
Sample Response: ```json result = Some( AccountInfo { nonce: 26, consumers: 2, providers: 1, sufficients: 0, data: AccountData { free: 3809329880703171553761, reserved: 2100000000000000000, frozen: 1008370553028965837506, flags: ExtraFlags( 170141183460469231731687303715884105728, ), }, }, ) ```
#### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" prim "github.com/availproject/avail-go-sdk/primitives" "github.com/availproject/avail-go-sdk/sdk" syPallet "github.com/availproject/avail-go-sdk/metadata/pallets/system" "github.com/availproject/avail-go-sdk/primitives" ) func main() { // Initialize the SDK sdk, err := sdk.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash latestBlockHash, err := sdk.Client.BestBlockHash() if err != nil { log.Fatalf("Failed to get latest block hash: %v", err) } // Initialize the block storage blockStorage, err := sdk.Client.StorageAt(prim.Some(latestBlockHash)) if err != nil { log.Fatalf("Failed to get block storage: %v", err) } // Create the account ID accountId, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } // Fetch the account data storage := syPallet.StorageAccount{} val, err := storage.Fetch(&blockStorage, accountId) if err != nil { log.Fatalf("Failed to fetch account: %v", err) } // Log the account data fmt.Println("Free Balance: ", val.Value.AccountData.Free.ToHuman()) fmt.Println("Reserved Balance: ", val.Value.AccountData.Reserved.ToHuman()) fmt.Println("Frozen Balance: ", val.Value.AccountData.Frozen.ToHuman()) fmt.Println("Account information fetched successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" > go mod tidy > ``` > > and try again. ### Create an App ID > **Note** > > **LOOKING TO READ MORE ABOUT WHAT APPIDs ARE?** > You can go through [this page in our docs](/docs/da/concepts/app-ids) for a deeper understanding of how > AppIDs work on Avail. > **Note** > > **LOOKING FOR PROGRAMMATIC INSTRUCTIONS?** > You can check out our [API reference](/docs/da/api-reference/avail-node-api/da-create-application-key) for the same. The easiest way to set up your own `AppID` on Avail DA is to use our [online AppID generator](https://appid.availproject.org/). ## Check the next available `AppID` > **Note** > > Each `appID` consists of 3 fields: > > * `key`: This is a string that is the name of the `appID`. Each `appID` should have a unique name. > * `owner`: This is the address of the account that created the `appID`. A single address can create multiple `AppIds`. > * `id`: This is the unique integer index of the `appID`. It is incremented by 1 everytime a new `appID` is created. Whenever a new > `appID` is created, it is automatically assigned the next available `id`. 1. Go to [appid.availproject](https://appid.availproject.org/) and select the correct network from the dropdown. 2. Click on `Search` and you will see a list of already existing `AppIDs` on the network. > If you choose to create a new `AppID`, it's `id` will be the next integer in the sequence. ## How to register my own `AppID`? 1. You need to connect an Avail DA account to the website. Click on `Connect wallet` to do so. > **Note** > > If you don't have an Avail DA wallet, you can follow our docs on [setting up a new wallet](/docs/da/user-guides/accounts#creating-an-account-on-avail-da). 2. Once connected, simply give your `AppID` a name, click on `Create AppID` and approve the transaction in your wallet to create the `AppID`. ## A few more things of note 1. As stated earlier, the `key` and `id` fields of every `AppID` are unique. This means if you try to create an `AppID` with the same `key` as an existing one, the operation will fail. 2. If you're a developer and are looking for more programmatic instructions, you can check out our [API reference](/docs/da/api-reference/avail-node-api/da-create-application-key). ### Testnet Faucet The Avail testnet faucet will be living at [faucet.avail.tools](https://faucet.avail.tools/) for the foreseeable future. As of now, this is the only officially supported faucet for Avail DA. > **Note** > > PLEASE NOTE > The faucet is designed to distribute small amounts of AVAIL for testing purposes, not large quantities for validator bonding or similar activities. > The current maximum balance a requesting address can have is 100 AVAIL. ## How to Use the Faucet 1. Create a Substrate account using a compatible wallet. We recommend [SubWallet](https://www.subwallet.app/), [Talisman](https://www.talisman.xyz/), or [PolkadotJS](https://polkadot.js.org/). 2. Go to [faucet.avail.tools](https://faucet.avail.tools/).

Avail online Faucet

3. Choose the chain you want to receive your tokens on. The default option will be `Turing`. 4. Enter the address where you want to receive your `AVAIL`. The address will begin with `5`. 5. You might see a captcha when trying out the faucet in production. Complete the captcha to get your tokens. And that's it. You should receive a small amount of AVAIL in your account shortly. ### Query Balances ## Setting up the dev environment In this guide we will use Avail's dedicated SDKs to interact with the [Turing testnet](/docs/da/networks). To set up a dev environment for the SDK of your choice, please follow the steps [outlined here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). ## Querying the balance of an account To query basic information about an account, including it's balance, you need to call the `system_account` extrinsic from the `system` pallet on an Avail node. #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function getAccountBalance() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Address to check balance for const address = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log(`Checking balance for address: ${address}`); // Get the current block hash const blockHash = await sdk.client.bestBlockHash(); // Get storage at the current block const storageAt = await sdk.client.storageAt(blockHash); // Fetch account information const accountInfo = await Pallets.SystemStorage.Account.fetch(storageAt, address); // Format balances in AVAIL (dividing by 10^18) const free = accountInfo.value.accountData.free.toString(); const reserved = accountInfo.value.accountData.reserved.toString(); const frozen = accountInfo.value.accountData.frozen.toString(); console.log("The following balances are in the smallest units, divide by 10^18 to get the balance in AVAIL"); console.log(`Free Balance: ${free}`); console.log(`Reserved Balance: ${reserved}`); console.log(`Frozen Balance: ${frozen}`); console.log("Account information fetched successfully"); process.exit(0); } // Execute the function getAccountBalance(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use avail_rust::prelude::*; use core::str::FromStr; pub async fn system_account() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let account_id = AccountId::from_str("5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg").unwrap(); let block_hash = sdk.client.best_block_hash().await?; let storage = sdk.client.storage().at(block_hash); let address = avail::storage().system().account(account_id); let result = storage.fetch(&address).await?; if let Some(account) = result { println!("Consumers: {}", account.consumers); println!("Data: {:?}", account.data); println!("Nonce: {}", account.nonce); println!("Providers: {}", account.providers); println!("Sufficients: {}", account.sufficients); } Ok(()) } // Add a main function to call system_account #[tokio::main] async fn main() { if let Err(e) = system_account().await { eprintln!("Error: {:?}", e); } else { println!("Account information fetched successfully"); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" prim "github.com/availproject/avail-go-sdk/primitives" "github.com/availproject/avail-go-sdk/sdk" syPallet "github.com/availproject/avail-go-sdk/metadata/pallets/system" "github.com/availproject/avail-go-sdk/primitives" ) func main() { // Initialize the SDK sdk, err := sdk.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Get the latest block hash latestBlockHash, err := sdk.Client.BestBlockHash() if err != nil { log.Fatalf("Failed to get latest block hash: %v", err) } // Initialize the block storage blockStorage, err := sdk.Client.StorageAt(prim.Some(latestBlockHash)) if err != nil { log.Fatalf("Failed to get block storage: %v", err) } // Create the account ID accountId, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } // Fetch the account data storage := syPallet.StorageAccount{} val, err := storage.Fetch(&blockStorage, accountId) if err != nil { log.Fatalf("Failed to fetch account: %v", err) } // Log the account data fmt.Println("Free Balance: ", val.Value.AccountData.Free.ToHuman()) fmt.Println("Reserved Balance: ", val.Value.AccountData.Reserved.ToHuman()) fmt.Println("Frozen Balance: ", val.Value.AccountData.Frozen.ToHuman()) fmt.Println("Account information fetched successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" name="cmd7" > go mod tidy > ``` > > and try again. #### AvailApps explorer The following instructions will guide you on how to query the balance of an account using the AvailApps explorer: 1. Go to the [`chains state` page](https://explorer.avail.so/#/chainstate) on the AvailApps explorer. 2. The balance of an account can be queried by calling the `account(AccountId32)` method from within the `system` pallet. Select the `system` pallet from the dropdown on the left, and the `account(AccountId32)` method from the dropdown on the right. 3. Either paste the address of an account in the `AccountId32` field or select an explorer-connected account from the dropdown. 4. Leave the `blockhash` field empty (This will query the latest balance of the account), and click on the `+` button near the top-right. 5. And that's it. You just used the `AvailApps` explorer to query the balance of an account on the Avail network. You can query other methods in a similar way. Your response should look something like this:
Sample Response: ``` { nonce: '109', consumers: '2', providers: '1', sufficients: '0', data: { free: '1,000,000,000,000', reserved: '100,000,300,000,000,000,000', frozen: '100,000,000,000,000,000,000', flags: '170,141,183,460,469,231,731,687,303,715,884,105,728' } } Free balance: 28.3046577073 AVAIL ```
## Fetch account information using a simple `curl` request via the Subscan API 1. The [Subscan API](https://support.subscan.io/) can be used to make API queries to the Subscan indexer to make various kinds of queries. 2. Subscan supports a variety of Substrate-based chains, including Avail DA mainnet and the Turing testnet. 3. You can either use their publicly available endpoints for the Avail networks, or use a [dedicated endpoint](https://pro.subscan.io/). 4. The examples below use publicly available Subscan API endpoints for both networks. #### avail-mainnet 1. Open a terminal and run the following command: ```bash filename="terminal" name="cmd8" curl --location --request POST 'https://avail.api.subscan.io/api/v2/scan/search' \ --header 'Content-Type: application/json' \ --data-raw '{ "key": "" }' ``` 2. Replace `` with the address you want to query.
Sample Response: ```json filename="JSON response" { "code": 0, "message": "Success", "generated_at": 1741796675, "data": { "account": { "address": "5HbUMBK8SBKH22qrm2sRDtWNtfyT331tUHpKkFMUKyirkJ6G", "balance": "169389.0977233184983879", "lock": "168914.456888072538284769", "balance_lock": "168914.456888072538284769", "is_evm_contract": false, "account_display": { "address": "5HbUMBK8SBKH22qrm2sRDtWNtfyT331tUHpKkFMUKyirkJ6G" }, "substrate_account": null, "evm_account": "", "registrar_info": null, "count_extrinsic": 0, "nft_amount": "0", "extra": null, "display": "", "web": "", "riot": "", "email": "", "legal": "", "twitter": "", "github": "", "matrix": "", "discord": "", "judgements": null, "reserved": "13000000000000000000", "bonded": "168914456888072538284769", "unbonding": "0", "democracy_lock": "0", "conviction_lock": "0", "election_lock": "0", "staking_info": null, "nonce": 0, "role": "validator", "stash": "5HbUMBK8SBKH22qrm2sRDtWNtfyT331tUHpKkFMUKyirkJ6G", "is_council_member": false, "is_techcomm_member": false, "is_registrar": false, "is_fellowship_member": false, "is_module_account": false, "assets_tag": null, "is_erc20": false, "is_erc721": false, "vesting": null, "proxy": { "proxy_account": [ { "account_display": { "address": "5HmgLcTCi2trnz4AeEiWs4ngAjALu7o4mFnpKdMBnA8jhFnq" }, "proxy_type": "Staking" } ] }, "multisig": { "multi_account_member": [ { "address": "5DfE73hjEYs44JHsuMKzrTMBzkEb6fosaV5xSUEVNjrHwqdB" }, { "address": "5DtGLPULvxXoSPvVv2YZdWmCJy8eEYnWj7MwPpdwGgDnFiua" }, { "address": "5DyHKiRY2ssTWU4CtbbEPoYFmNKaN2X39KRcgb33fnZqk2Yd" } ], "threshold": 2 }, "delegate": null } } } ```
#### turing-testnet 1. Open a terminal and run the following command: ```bash filename="terminal" name="cmd9" curl --location --request POST 'https://avail-turing.api.subscan.io/api/v2/scan/search' \ --header 'Content-Type: application/json' \ --data-raw '{ "key": "" }' ``` 2. Replace `` with the address you want to query.
Sample Response: ```json filename="JSON response" { "code": 0, "message": "Success", "generated_at": 1741798906, "data": { "account": { "address": "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk", "balance": "16360.7888064893714931", "lock": "1131.93873839810825155", "balance_lock": "1131.93873839810825155", "is_evm_contract": false, "account_display": { "address": "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk" }, "substrate_account": null, "evm_account": "", "registrar_info": null, "count_extrinsic": 54, "nft_amount": "0", "extra": null, "display": "", "web": "", "riot": "", "email": "", "legal": "", "twitter": "", "github": "", "matrix": "", "discord": "", "judgements": null, "reserved": "15100000000000000000", "bonded": "1131938738398108251550", "unbonding": "0", "democracy_lock": "0", "conviction_lock": "0", "election_lock": "0", "staking_info": null, "nonce": 54, "role": "nominator", "stash": "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk", "is_council_member": false, "is_techcomm_member": false, "is_registrar": false, "is_fellowship_member": false, "is_module_account": false, "assets_tag": null, "is_erc20": false, "is_erc721": false, "is_pool_member": true, "vesting": null, "proxy": { "proxy_account": [ { "account_display": { "address": "5GvF6GLPuxbseH5qC9w8doUiCMnT4vGvY3Rznu3Fktdw4N45" }, "proxy_type": "NonTransfer" } ] }, "multisig": { "multi_account": [ { "address": "5DSCqHHH3whUA3xgkyVSekXB36Gc47SwsJEHLuab5RnFvNua" } ] }, "delegate": null, "nomination_pool_balance": [ { "pool_id": 3, "bonded": "100000000000000000000", "unbonding": "0", "claimable": "0" } ] } } } ```
### Read & Write Data > **Note** > > **BEFORE YOU BEGIN** > We recommend you go through these two pages in our docs before proceeding: > > 1. [`Get Testnet Tokens`](/docs/da/build/interact/faucet): To help you get set with some `AVAIL` tokens on the Turing testnet. > 2. [`Create an AppID`](/docs/da/build/interact/app-id): The guide below focusses on reading & submitting data on a particular AppID. It will help > to be familiar with the concept. ## Setting up the dev environment In this guide we will use some dedicated libraries to interact with Avail DA. To set up a dev environment for `avail-js`, please follow the steps [outlined here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). ## Submitting data to Avail DA #### avail-js 1. Create a file named `your-file-name.ts` 2. Paste the following code into the file: This piece of code submits: * A string named `data` to Avail DA * to the `appID` of 89 * We expect devs to submit data to their own specific `appID`s. ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, Pallets } from 'avail-js-sdk'; dotenv.config(); export async function submitData() { // Initialize the SDK with a public Turing testnet endpoint // You can always switch it out with your own endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Loading seed phrase and creating an account derived from the seed const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Account Address: ", account.address); // Replace with your own AppID const appId = 89; console.log(`Submitting data to App Id: ${appId}`); // Create data submission transaction const data = "My Data Submission"; const tx = sdk.tx.dataAvailability.submitData(data); console.log("Submitting transaction with data..."); // Execute and wait for inclusion with app_id const res = await tx.executeWaitForInclusion(account, { app_id: appId }); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } // Extract event data if (res.events === undefined) throw new Error("No events found"); // Transaction Details console.log( `Block Hash: ${res.blockHash}, Block Number: ${res.blockNumber}, Tx Hash: ${res.txHash}, Tx Index: ${res.txIndex}` ); // Find DataSubmitted event const event = res.events.findFirst(Pallets.DataAvailabilityEvents.DataSubmitted); if (event === undefined) throw new Error("DataSubmitted event not found"); console.log(`Data submitted successfully:`); console.log(`Who: ${event.who}`); console.log(`DataHash: ${event.dataHash}`); console.log("Data submission completed successfully"); process.exit(0); } submitData() ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Create a file named `main.rs` 2. Paste the following code into the file: This piece of code submits: * A string named `data` to Avail DA * to the `appID` of 1 * We expect devs to submit data to their own specific `appID`s. ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; type DataSubmissionCall = avail::data_availability::calls::types::SubmitData; pub async fn submit_data() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Please note that the tx will fail if this application key does not exist let my_application_key = 1; // Data Submission let data = String::from("My Data").into_bytes(); let options = Options::new().app_id(my_application_key); let tx = sdk.tx.data_availability.submit_data(data); let res = tx.execute_and_watch_inclusion(&account, options).await?; assert_eq!(res.is_successful(), Some(true), "Transactions must be successful"); println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); // Decoding let decoded = res.decode_as::().await?; let Some(decoded) = decoded else { return Err("Failed to get Data Submission Call data".into()); }; let data = to_ascii(decoded.data.0).unwrap(); println!("Call data: {:?}", data); println!("Data Submission finished correctly"); Ok(()) } // Add a main function to call submit_data #[tokio::main] async fn main() { if let Err(e) = submit_data().await { eprintln!("Error: {:?}", e); } } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Create a file named `main.go` 2. Paste the following code into the file: This piece of code submits: * A string to Avail DA * to the `appID` of 89 * We expect devs to submit data to their own specific `appID`s. ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Submit data to Avail appId := uint32(89) tx := sdk.Tx.DataAvailability.SubmitData([]byte("Submitting some data using avail-go-sdk")) res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions().WithAppId(appId)) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) fmt.Println("Data submission completed successfully") } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd6" go run main.go ``` #### AvailApps explorer 1. Go to the [`extrinsics` page](https://explorer.avail.so/#/extrinsics) on the AvailApps explorer. 2. Select an account which has funds on the network. 3. Select the `dataAvailability` pallet from the dropdown on the left. 4. Select the `submitData` extrinsic from the dropdown on the right. 5. Enter the data you want to submit in the `data` field.

submitting data using the explorer

6. Click on `Submit Transaction` and fill in the details in the pop-up window.

filling out the tx details

> **Note** > > The `appID` should be an integer that represents a valid AppID on the network. > To check out how to create an AppID on Avail, [refer to this page](/docs/da/build/interact/app-id). 7. Click on `Sign and Submit` and approve the transaction in your wallet. ## Fetch data submission transactions from Avail DA ### Fetch data submissions using transaction hash and block hash > You can read back your submitted data from Avail DA using the `blockHash` and `txHash` of the transaction. #### avail-js 1. Create a file named `your-file-name.ts` 2. Paste the following code into the file: ```typescript showLineNumbers filename="avail-js" name="cmd7" import { SDK, Block } from 'avail-js-sdk'; export async function readDataByHash() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Transaction hash and block hash to look up const txHash = "0x70d8cc521c341d717f5b11d1898fc7a21f9d894c3617929aaabaea71c4814911"; const blockHash = "0xd5f95593d91a581d7ce7b8717789298345be4be47e75ba93e7159cfe23083a7b"; console.log(`Looking up transaction: ${txHash}`); console.log(`In block: ${blockHash}`); // Create a Block object for the specified block hash const block = await Block.New(sdk.client, blockHash); // Get data submissions for the specified transaction hash const blobs = block.dataSubmissions({ txHash: txHash }); console.log(`Found ${blobs.length} data submission(s)`); // Display information for each data blob if (blobs.length === 0) { console.log("No data submissions found for this transaction"); } else { console.log("\nData Submission Details:"); for (const blob of blobs) { console.log(`Tx Hash: ${blob.txHash}`); console.log(`Tx Index: ${blob.txIndex}`); console.log(`Data (ASCII): ${blob.toAscii()}`); console.log(`App Id: ${blob.appId}`); console.log(`Signer: ${blob.txSigner}`); console.log("---"); } } console.log("Data retrieval completed successfully"); process.exit(0); } readDataByHash() ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd8" ts-node your-file-name.ts ``` #### avail-rust 1. Create a file named `main.rs` 2. Paste the following code into the file: ```rust showLineNumbers filename="avail-rust" name="cmd9" use avail_rust::prelude::*; pub async fn read_data_by_hash() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let block_hash = new_h256_from_hex("0xd5f95593d91a581d7ce7b8717789298345be4be47e75ba93e7159cfe23083a7b")?; let block = Block::new(&sdk.client, block_hash).await?; // All Block Blobs by Hash let tx_hash = new_h256_from_hex("0x70d8cc521c341d717f5b11d1898fc7a21f9d894c3617929aaabaea71c4814911")?; let blobs = block.data_submissions(Filter::new().tx_hash(tx_hash)); assert_eq!(blobs.len(), 1, ""); let blob = &blobs[0]; // Printout All Block Blobs by Hash let blob_data = blob.to_ascii().unwrap(); assert_eq!(blob.tx_hash, tx_hash, "Tx Hash must be the same"); println!( "Tx Hash: {:?}, Tx Index: {}, Data: {:?}, App Id: {}, Tx Singer: {:?}", blob.tx_hash, blob.tx_index, blob_data, blob.app_id, blob.ss58address(), ); println!("Data retrieval completed successfully"); Ok(()) } // Add a main function to call submit_data #[tokio::main] async fn main() { if let Err(e) = read_data_by_hash().await { eprintln!("Error: {:?}", e); } } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd10" cargo run ``` #### avail-go 1. Create a file named `main.go` 2. Paste the following code into the file: ```go showLineNumbers filename="avail-go" name="cmd11" package main import ( "fmt" "log" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } blockHash, err := primitives.NewBlockHashFromHexString("0xd5f95593d91a581d7ce7b8717789298345be4be47e75ba93e7159cfe23083a7b") if err != nil { log.Fatalf("Failed to create block hash: %v", err) } block, err := SDK.NewBlock(sdk.Client, blockHash) if err != nil { log.Fatalf("Failed to create block: %v", err) } // Block Blobs filtered by Transaction Hash txHash, err := primitives.NewH256FromHexString("0x70d8cc521c341d717f5b11d1898fc7a21f9d894c3617929aaabaea71c4814911") if err != nil { log.Fatalf("Failed to create transaction hash: %v", err) } blobs := block.DataSubmissions(SDK.Filter{}.WTxHash(txHash)) if err != nil { log.Fatalf("Failed to create data submissions: %v", err) } blob := &blobs[0] // Printout Block Blobs filtered by Transaction Hash accountId, err := primitives.NewAccountIdFromMultiAddress(blob.TxSigner) if err != nil { log.Fatalf("Failed to create account ID: %v", err) } fmt.Println(fmt.Sprintf(`Tx Hash: %v, Tx Index: %v, Data: %v, App Id: %v, Signer: %v,`, blob.TxHash, blob.TxIndex, string(blob.Data), blob.AppId, accountId.ToHuman())) fmt.Println("Data retrieval completed successfully") } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd12" go run main.go ``` ### Fetch data submissions using AppID > You can read back your submitted data from Avail DA using the `AppID`. #### avail-js 1. Create a file named `your-file-name.ts` 2. Paste the following code into the file: ```typescript showLineNumbers filename="avail-js" name="cmd13" import * as dotenv from 'dotenv'; import { SDK, Block } from 'avail-js-sdk'; dotenv.config(); export async function readDataByAppId() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // App ID and block hash to look up const appId = 89; const blockHash = "0xd5f95593d91a581d7ce7b8717789298345be4be47e75ba93e7159cfe23083a7b"; console.log(`Looking up data for App ID: ${appId}`); console.log(`In block: ${blockHash}`); // Create a Block object for the specified block hash const block = await Block.New(sdk.client, blockHash); // Get data submissions for the specified app ID const blobs = block.dataSubmissions({ appId: appId }); console.log(`Found ${blobs.length} data submission(s)`); // Display information for each data blob if (blobs.length === 0) { console.log("No data submissions found for this app ID"); } else { console.log("\nData Submission Details:"); for (const blob of blobs) { console.log(`Tx Hash: ${blob.txHash}`); console.log(`Tx Index: ${blob.txIndex}`); console.log(`Data (ASCII): ${blob.toAscii()}`); console.log(`App Id: ${blob.appId}`); console.log(`Signer: ${blob.txSigner}`); console.log("---"); } } console.log("Data retrieval completed successfully"); process.exit(0); } readDataByAppId() ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd14" ts-node your-file-name.ts ``` #### avail-rust 1. Create a file named `main.rs` 2. Paste the following code into the file: ```rust showLineNumbers filename="avail-rust" name="cmd15" use avail_rust::prelude::*; pub async fn read_data_by_appid() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let block_hash = new_h256_from_hex("0xd5f95593d91a581d7ce7b8717789298345be4be47e75ba93e7159cfe23083a7b")?; let block = Block::new(&sdk.client, block_hash).await?; // All Block Blobs by App Id let app_id = 89; let blobs = block.data_submissions(Filter::new().app_id(app_id)); // Printout All Block Blobs by App Id for blob in blobs { let blob_data = blob.to_ascii().unwrap(); println!( "Tx Hash: {:?}, Tx Index: {}, Data: {:?}, App Id: {}, Tx Singer: {:?}", blob.tx_hash, blob.tx_index, blob_data, blob.app_id, blob.ss58address(), ); } println!("Data retrieval completed successfully"); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = read_data_by_appid().await { eprintln!("Error: {:?}", e); } } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd16" cargo run ``` #### avail-go 1. Create a file named `main.go` 2. Paste the following code into the file: ```go showLineNumbers filename="avail-go" name="cmd17" package main import ( "fmt" "log" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } blockHash, err := primitives.NewBlockHashFromHexString("0x94746ba186876d7407ee618d10cb6619befc59eeb173cacb00c14d1ff492fc58") if err != nil { log.Fatalf("Failed to create block hash: %v", err) } block, err := SDK.NewBlock(sdk.Client, blockHash) if err != nil { log.Fatalf("Failed to create block: %v", err) } // Block Blobs filtered by App Id appId := uint32(2) blobs := block.DataSubmissions(SDK.Filter{}.WAppId(appId)) if err != nil { log.Fatalf("Failed to create data submissions: %v", err) } // Printout Block Blobs filtered by App Id for _, blob := range blobs { if blob.AppId != appId { log.Fatalf("Transaction App Ids are not the same.") } accountId, err := primitives.NewAccountIdFromMultiAddress(blob.TxSigner) if err != nil { log.Fatalf("Failed to create account ID: %v", err) } fmt.Println(fmt.Sprintf(`Tx Hash: %v, Tx Index: %v, Data: %v, App Id: %v, Signer: %v,`, blob.TxHash, blob.TxIndex, string(blob.Data), blob.AppId, accountId.ToHuman())) } fmt.Println("Data retrieval completed successfully") } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd18" go run main.go ``` ### Fetch all data submissions for a given block Here is a complete example of how to fetch all the data submissions for a given block: #### avail-js ```typescript showLineNumbers filename="avail-js" name="cmd19" import * as dotenv from 'dotenv'; import { SDK, Block } from 'avail-js-sdk'; dotenv.config(); export async function readDataByBlock() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Block hash to look up const blockHash = "0x94746ba186876d7407ee618d10cb6619befc59eeb173cacb00c14d1ff492fc58"; console.log(`Looking up all data submissions in block: ${blockHash}`); // Create a Block object for the specified block hash const block = await Block.New(sdk.client, blockHash); // Get all data submissions in the block const blobs = block.dataSubmissions(); console.log(`Found ${blobs.length} data submission(s)`); // Display information for each data blob if (blobs.length === 0) { console.log("No data submissions found in this block"); } else { console.log("\nData Submission Details:"); for (const blob of blobs) { console.log(`Tx Hash: ${blob.txHash}`); console.log(`Tx Index: ${blob.txIndex}`); console.log(`Data (ASCII): ${blob.toAscii()}`); console.log(`App Id: ${blob.appId}`); console.log(`Signer: ${blob.txSigner}`); console.log("---"); } } console.log("Data retrieval completed successfully"); process.exit(0); } // Execute the function readDataByBlock(); ``` 6. Run the script using the following command: ```bash filename="terminal" name="cmd20" ts-node your-file-name.ts ``` #### avail-rust ```rust showLineNumbers filename="avail-rust" name="cmd21" use avail_rust::prelude::*; pub async fn read_data_by_block() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; let block_hash = new_h256_from_hex("0x94746ba186876d7407ee618d10cb6619befc59eeb173cacb00c14d1ff492fc58")?; let block = Block::new(&sdk.client, block_hash).await?; // All Block Blobs let blobs = block.data_submissions(Filter::default()); // Printout All Block Blobs for blob in blobs { let blob_data = blob.to_ascii().unwrap(); println!( "Tx Hash: {:?}, Tx Index: {}, Data: {:?}, App Id: {}, Tx Singer: {:?}", blob.tx_hash, blob.tx_index, blob_data, blob.app_id, blob.ss58address(), ); } println!("Data retrieval completed successfully"); Ok(()) } #[tokio::main] async fn main() { if let Err(e) = read_data_by_block().await { eprintln!("Error: {:?}", e); } } ``` 6. Run the script using the following command: ```bash filename="terminal" name="cmd22" cargo run ``` #### avail-go ```go showLineNumbers filename="avail-go" name="cmd23" package main import ( "fmt" "log" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } blockHash, err := primitives.NewBlockHashFromHexString("0x94746ba186876d7407ee618d10cb6619befc59eeb173cacb00c14d1ff492fc58") if err != nil { log.Fatalf("Failed to create block hash: %v", err) } block, err := SDK.NewBlock(sdk.Client, blockHash) if err != nil { log.Fatalf("Failed to create block: %v", err) } // All Block Blobs blobs := block.DataSubmissions(SDK.Filter{}) fmt.Println(len(blobs)) // Printout All Block Blobs for _, blob := range blobs { accountId, err := primitives.NewAccountIdFromMultiAddress(blob.TxSigner) if err != nil { log.Fatalf("Failed to create account ID: %v", err) } fmt.Println(fmt.Sprintf(`Tx Hash: %v, Tx Index: %v, Data: %v, App Id: %v, Signer: %v,`, blob.TxHash, blob.TxIndex, string(blob.Data), blob.AppId, accountId.ToHuman())) } fmt.Println("Data retrieval completed successfully") } ``` 6. Run the script using the following command: ```bash filename="terminal" name="cmd24" go run main.go ``` ## Fetch all types of transactions on Avail DA ### Fetch all transactions by a particular signer in a block Here is a complete example of how to fetch all the transactions by a particular signer in a particular block: #### avail-js 1. Create a file named `your-file-name.ts` 2. Paste the following code into your file: ```typescript showLineNumbers filename="avail-js" name="cmd25" import { SDK, Block } from 'avail-js-sdk'; export async function fetchTransactionsBySigner() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Block hash and signer address to look up const blockHash = "0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1"; const signer = "5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg"; console.log(`Looking up transactions by signer: ${signer}`); console.log(`In block: ${blockHash}`); // Create a Block object for the specified block hash const block = await Block.New(sdk.client, blockHash); // Get transactions for the specified signer const blockTxs = block.transactions({ txSigner: signer }); console.log(`Found ${blockTxs.length} transaction(s)`); // Display information for each transaction if (blockTxs.length === 0) { console.log("No transactions found for this signer"); } else { console.log("\nTransaction Details:"); for (const tx of blockTxs) { console.log(`Pallet Name: ${tx.palletName()}`); console.log(`Pallet Index: ${tx.palletIndex()}`); console.log(`Call Name: ${tx.callName()}`); console.log(`Call Index: ${tx.callIndex()}`); console.log(`Tx Hash: ${tx.txHash()}`); console.log(`Tx Index: ${tx.txIndex()}`); console.log(`Signer: ${tx.ss58Address()}`); console.log("---"); } } console.log("Transaction retrieval completed successfully"); process.exit(0); } // Execute the function fetchTransactionsBySigner(); ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd26" ts-node your-file-name.ts ``` #### avail-rust 1. Create a file named `main.rs` 2. Paste the following code into your file: ```rust showLineNumbers filename="avail-rust" name="cmd27" use avail_rust::prelude::*; pub async fn fetch_transactions_by_signer() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Enter the block hash you want to fetch transactions from let block_hash = new_h256_from_hex("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1")?; // Fetch the Block let block = Block::new(&sdk.client, block_hash).await?; // Fetch All Transaction filtered by Signer let account_id = account_id_from_str("5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg")?; let block_transactions = block.transactions(Filter::new().tx_signer(account_id.clone())); // Printout Block Transactions made by Signer for tx in block_transactions.iter() { println!( "Pallet Name: {:?}, Pallet Index: {}, Call Name: {:?}, Call Index: {:?}, Tx Hash: {:?}, Tx Index: {}", tx.pallet_name(), tx.pallet_index(), tx.call_name(), tx.call_index(), tx.tx_hash(), tx.tx_index() ); println!( "Tx Signer: {:?}, App Id: {:?}, Tip: {:?}, Mortality: {:?}, Nonce: {:?}", tx.ss58address(), tx.app_id(), tx.tip(), tx.mortality(), tx.nonce(), ); } println!("Transaction retrieval completed successfully"); Ok(()) } #[tokio::main] async fn main() -> Result<(), ClientError> { fetch_transactions_by_signer().await?; Ok(()) } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd28" cargo run ``` #### avail-go 1. Create a file named `main.go` 2. Paste the following code into your file: ```go showLineNumbers filename="avail-go" name="cmd29" package main import ( "fmt" "log" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } blockHash, err := primitives.NewBlockHashFromHexString("0x75a6c54bb5ea904e47fa151956992d7cf543bc7c936d78488e311db8e10397c1") if err != nil { log.Fatalf("Failed to create block hash: %v", err) } block, err := SDK.NewBlock(sdk.Client, blockHash) if err != nil { log.Fatalf("Failed to create block: %v", err) } // Create an account ID accountId, err := primitives.NewAccountIdFromAddress("5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg") if err != nil { log.Fatalf("Failed to create account ID: %v", err) } // All Transaction filtered by Signer blockTxs := block.Transactions(SDK.Filter{}.WTxSigner(accountId)) fmt.Println("Transaction Count: ", len(blockTxs)) // Printout Block Transactions filtered by Signer for _, tx := range blockTxs { fmt.Println(fmt.Sprintf(`Pallet Name: %v, Pallet Index: %v, Call Name: %v, Call Index: %v, Tx Hash: %v, Tx Index: %v`, tx.PalletName(), tx.PalletIndex(), tx.CallName(), tx.CallIndex(), tx.TxHash(), tx.TxIndex())) fmt.Println(fmt.Sprintf(`Tx Signer: %v, App Id: %v, Tip: %v, Mortality: %v, Nonce: %v`, tx.SS58Address(), tx.AppId(), tx.Tip(), tx.Mortality(), tx.Nonce())) } fmt.Println("Transaction retrieval completed successfully") } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd30" go run main.go ``` ### Fetch all transactions from a particular block Here is a complete example of how to fetch all the transactions from a particular block: #### avail-js 1. Create a file named `your-file-name.ts` 2. Paste the following code into your file: ```typescript showLineNumbers filename="avail-js" name="cmd31" import { SDK, Block } from 'avail-js-sdk'; export async function fetchAllTransactions() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Block hash to look up const blockHash = "0x9016d7953c88115534a602f2d2548c70c4f5b378d86f4bedda82be2655467c5d"; console.log(`Looking up all transactions in block: ${blockHash}`); // Create a Block object for the specified block hash const block = await Block.New(sdk.client, blockHash); // Get all transactions in the block const blockTxs = block.transactions(); console.log(`Found ${blockTxs.length} transaction(s)`); // Display information for each transaction if (blockTxs.length === 0) { console.log("No transactions found in this block"); } else { console.log("\nTransaction Details:"); for (const tx of blockTxs) { console.log(`Pallet Name: ${tx.palletName()}`); console.log(`Pallet Index: ${tx.palletIndex()}`); console.log(`Call Name: ${tx.callName()}`); console.log(`Call Index: ${tx.callIndex()}`); console.log(`Tx Hash: ${tx.txHash()}`); console.log(`Tx Index: ${tx.txIndex()}`); console.log(`Signer: ${tx.ss58Address()}`); console.log("---"); } } console.log("Transaction retrieval completed successfully"); process.exit(0); } // Execute the function fetchAllTransactions(); ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd32" ts-node your-file-name.ts ``` #### avail-rust 1. Create a file named `main.rs` 2. Paste the following code into your file: ```rust showLineNumbers filename="avail-rust" name="cmd33" use avail_rust::prelude::*; pub async fn fetch_all_transactions() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Enter the block hash you want to fetch transactions from let block_hash = new_h256_from_hex("0x9016d7953c88115534a602f2d2548c70c4f5b378d86f4bedda82be2655467c5d")?; let block = Block::new(&sdk.client, block_hash).await?; // Fetch All Transactions let block_transactions = block.transactions(Filter::default()); // Printout Block Transactions for tx in block_transactions.iter() { println!( "Pallet Name: {:?}, Pallet Index: {}, Call Name: {:?}, Call Index: {:?}, Tx Hash: {:?}, Tx Index: {}", tx.pallet_name(), tx.pallet_index(), tx.call_name(), tx.call_index(), tx.tx_hash(), tx.tx_index() ); println!( "Tx Signer: {:?}, App Id: {:?}, Tip: {:?}, Mortality: {:?}, Nonce: {:?}", tx.ss58address(), tx.app_id(), tx.tip(), tx.mortality(), tx.nonce(), ); } println!("Transaction retrieval completed successfully"); Ok(()) } #[tokio::main] async fn main() -> Result<(), ClientError> { fetch_all_transactions().await?; Ok(()) } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd34" cargo run ``` #### avail-go 1. Create a file named `main.go` 2. Paste the following code into your file: ```go showLineNumbers filename="avail-go" name="cmd35" package main import ( "fmt" "log" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" ) func main() { sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } blockHash, err := primitives.NewBlockHashFromHexString("0x9016d7953c88115534a602f2d2548c70c4f5b378d86f4bedda82be2655467c5d") if err != nil { log.Fatalf("Failed to create block hash: %v", err) } block, err := SDK.NewBlock(sdk.Client, blockHash) if err != nil { log.Fatalf("Failed to create block: %v", err) } // Fetch All Transactions blockTxs := block.Transactions(SDK.Filter{}) fmt.Println("Transaction Count: ", len(blockTxs)) // Printout Block Transactions for _, tx := range blockTxs { fmt.Println(fmt.Sprintf(`Pallet Name: %v, Pallet Index: %v, Call Name: %v, Call Index: %v, Tx Hash: %v, Tx Index: %v`, tx.PalletName(), tx.PalletIndex(), tx.CallName(), tx.CallIndex(), tx.TxHash(), tx.TxIndex())) fmt.Println(fmt.Sprintf(`Tx Signer: %v, App Id: %v, Tip: %v, Mortality: %v, Nonce: %v`, tx.SS58Address(), tx.AppId(), tx.Tip(), tx.Mortality(), tx.Nonce())) } fmt.Println("Transaction retrieval completed successfully") } ``` 3. Run the script using the following command: ```bash filename="terminal" name="cmd36" go run main.go ``` ## Estimate fees for your data submission The `avail-js` SDK provides a method to estimate the cost of submitting a particular piece of data to Avail DA. Here is how you can use it: #### avail-js ```typescript showLineNumbers filename="avail-js" name="cmd37" import { initialize, disconnect } from "avail-js-sdk"; const calculateCost = async () => { // Initialize the avail sdk providerEndpoint const providerEndpoint = await initialize("wss://turing-rpc.avail.so/ws"); // Dummy sender - insert any address const sender = "5CDGXH8Q9DzD3TnATTG6qm6f4yR1kbECBGUmh2XbEBQ8Jfa5"; //10^18 decimals to denominate to AVAIL const DECIMAL = 1000000000000000000; // Input the data let data = "This is a random piece of string data!!!"; //Get the estimated cost in AVAIL const cost = await providerEndpoint.tx.dataAvailability.submitData(data).paymentInfo(sender); const costInAvail = (parseInt(cost.partialFee.toString()) / DECIMAL).toFixed(6); console.log(`Estimated Fees: ${costInAvail} AVAIL`); await disconnect(); }; calculateCost(); ``` 2. Run the script using the following command: ```bash filename="terminal" name="cmd39" ts-node your-file-name.ts ``` ### Transfer Balances > **Note** > > **SETTING UP THE DEV ENVIRONMENT** > In this guide we will use Avail's dedicated SDKs to interact with the [Turing testnet](/docs/da/networks). > To set up a dev environment for the SDK of your choice, please follow the steps [outlined here](/docs/da/api-reference/avail-node-api#setting-up-the-dev-environment). ## Transferring funds programmatically You can transfer `AVAIL` from one account to another programmatically by calling any one of these three extrinsics from the `balances` pallet on an Avail node: 1. `balances_transferKeepAlive`: Transfers funds from one account to another, but does not allow the sender balance to dip below the existential deposit. 2. `balances_transferAllowDeath`: Transfers funds from one account to another, and allows the sender balance to dip below the existential deposit. 3. `balances_transferAll`: Transfers all funds from one account to another. > **Note** > > **EXISTENTIAL DEPOSIT** > Only accounts with a balance equal to or greater than the `existential deposit` are stored on the state trie. > The current value of the existential deposit is `0.000001 AVAIL`. > Any account whose balance dips below this amount is *'reaped'*. ### Transferring funds using `balances_transferKeepAlive` #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd1" import * as dotenv from 'dotenv'; import { Account, SDK, BN } from 'avail-js-sdk'; dotenv.config(); export async function transferKeepAlive() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Sender Address: ", account.address); // Destination address to send AVAIL to const destinationAddress = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log("Recipient Address: ", destinationAddress); // Amount to transfer: 12 AVAIL const amount = new BN('12000000000000000000'); // 12 with 18 zeroes console.log("Transfer Amount: 12 AVAIL"); // Create transfer transaction const tx = sdk.tx.balances.transferKeepAlive(destinationAddress, amount); console.log("Submitting transfer transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); console.log("Transfer completed successfully"); process.exit(0); } // Execute the function transferKeepAlive(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd2" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd3" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn transfer_keep_alive() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Executing the transaction let dest = AccountId::from_str("5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw").unwrap(); let amount = 1_000_000_000_000_000_000u128; // 1 AVAIL being transferred to the destination account let tx = sdk.tx.balances.transfer_keep_alive(dest, amount); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); println!("Transfer completed successfully"); Ok(()) } // Add a main function to call transfer_keep_alive #[tokio::main] async fn main() { if let Err(e) = transfer_keep_alive().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd4" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd5" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Destination address destAddress, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } dest := destAddress.ToMultiAddress() // Create a Balance from a string // The value is 10 AVAIL amount, err := metadata.NewBalanceFromString("10000000000000000000") if err != nil { log.Fatalf("Failed to create balance: %v", err) } // Transferring funds while ensuring the sender's account // retains a minimum balance tx := sdk.Tx.Balances.TransferKeepAlive(dest, amount) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) fmt.Println("Transfer completed successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd6" go run main.go --config config.json ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" name="cmd7" > go mod tidy > ``` > > and try again. #### AvailApps explorer 1. Go to the [`extrinsics` page](https://explorer.avail.so/#/extrinsics) on the AvailApps explorer. 2. Select an account which has funds on the network. 3. Select the `balances` pallet from the dropdown on the left, 4. Select the `transferKeepAlive` extrinsic from the dropdown on the right.

filling out the tx details

5. Fill in the `dest` field with the address of the account you want to send funds to. 6. Click on `Submit Transaction` , and then click on `Sign and Submit`.

filling out the tx details

> **Note** > > **DON'T CHANGE THE APPID** > Transferring funds from one address to the other is a chain-level operation, independent of any `AppID`. > All such operations are executed with the `AppID set to 0`. Your response should look something like this:
Sample Response: ``` From=5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg, To=5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk, Amount=10000000000000000000 TxHash=0x45a3ec18b96c2bff0d92d70ba5f0fa904b79a49610e845b72d16ccf7c094533d, BlockHash=0x9fa20525f0db53e144ff595f00728611d60bd5d5e597f07b82123301067e90be ```
### Transferring funds using `balances_transferAllowDeath` #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd8" import * as dotenv from 'dotenv'; import { Account, SDK, BN } from 'avail-js-sdk'; dotenv.config(); export async function transferAllowDeath() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Sender Address: ", account.address); // Destination address to send AVAIL to const destinationAddress = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log("Recipient Address: ", destinationAddress); // Amount to transfer: 12.345 AVAIL const amount = new BN('12345000000000000000'); // Create transfer transaction const tx = sdk.tx.balances.transferAllowDeath(destinationAddress, amount); console.log("Submitting transfer transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); console.log("Transfer completed successfully"); process.exit(0); } // Execute the function transferAllowDeath(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd9" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd10" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn transfer_allow_death() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Executing the transaction let dest = AccountId::from_str("5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw").unwrap(); let amount = 12_345_000_000_000_000_000u128; // 12.345 AVAIL being transferred to the destination account let tx = sdk.tx.balances.transfer_allow_death(dest, amount); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); println!("Transfer completed successfully"); Ok(()) } // Add a main function to call transfer_allow_death #[tokio::main] async fn main() { if let Err(e) = transfer_allow_death().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd11" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd12" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/metadata" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Destination address destAddress, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } dest := destAddress.ToMultiAddress() // Create a Balance from a string // The value is 10 AVAIL amount, err := metadata.NewBalanceFromString("10000000000000000000") if err != nil { log.Fatalf("Failed to create balance: %v", err) } // Transferring funds without the // necessary checks of keeping the sender's account alive tx := sdk.Tx.Balances.TransferAllowDeath(dest, amount) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) fmt.Println("Transfer completed successfully") } ``` 2. Run the code using: ```bash filename="terminal" name="cmd13" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" name="cmd14" > go mod tidy > ``` > > and try again. #### AvailApps explorer > **Note** > > Follow the same steps as before to use this extrinsic from the AvailApps explorer. > The only difference being that you need to select `balances_transferAllowDeath` from the dropdown. Your response should look something like this:
Sample Response: ``` From=5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg, To=5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw, Amount=12000000000000000000 MaybeKilled=undefined TxHash=0x4be89fffca3b7849066c3a7b6b29af318caa49ca12a1ba17610b0a30d97fd30e, BlockHash=0x861531ee9512849cec0bde5294bb65098424c84e3ab64b6c25722574370d8224 ```
### Transferring funds using `balances_transferAll` #### avail-js 1. Inside `your-file-name.ts`, add the following code: ```typescript showLineNumbers filename="avail-js" name="cmd15" import * as dotenv from 'dotenv'; import { Account, SDK } from 'avail-js-sdk'; dotenv.config(); export async function transferAll() { // Initialize SDK with Turing endpoint const sdk = await SDK.New('wss://turing-rpc.avail.so/ws'); // Create account from seed in .env file const seed = process.env.SEED; if (!seed) { throw new Error("SEED environment variable is not set"); } // Create account from seed const account = Account.new(seed); console.log("Sender Address: ", account.address); // Destination address to send all available AVAIL to const destinationAddress = "5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk"; console.log("Recipient Address: ", destinationAddress); // Setting this value to false will reap your account const keepAlive = true; // Create transfer all transaction const tx = sdk.tx.balances.transferAll(destinationAddress, keepAlive); console.log("Submitting transfer all transaction..."); // Execute and wait for inclusion const res = await tx.executeWaitForInclusion(account, {}); // Check if transaction was successful const isOk = res.isSuccessful(); if (isOk === undefined) { throw new Error("Cannot check if transaction was successful"); } else if (!isOk) { throw new Error("Transaction failed"); } console.log("Transfer all completed successfully"); console.log(`Transaction Hash: ${res.txHash}`); console.log(`Block Hash: ${res.blockHash}`); console.log(`Block Number: ${res.blockNumber}`); process.exit(0); } // Execute the function transferAll(); ``` 2. Run the code using: ```bash filename="terminal" name="cmd16" ts-node your-file-name.ts ``` #### avail-rust 1. Inside `main.rs`, add the following code: ```rust showLineNumbers filename="avail-rust" name="cmd17" use dotenvy::dotenv; use std::env; use avail_rust::prelude::*; use core::str::FromStr; pub async fn transfer_all() -> Result<(), ClientError> { // Create a new SDK instance let sdk = SDK::new("wss://turing-rpc.avail.so/ws").await?; // Loading seed phrase and creating an account derived from the seed dotenv().ok(); let seed = env::var("SEED").expect("SEED environment variable is not set"); let account = account::from_secret_uri(&seed)?; println!("Account Address: {}", account.public_key().to_account_id()); // Executing the transaction let dest = AccountId::from_str("5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw").unwrap(); // Please take note of the `keep_alive` bool parameter // If set to true, the transfer transaction will leave the origin account with a small balance // that is above the existential deposit and prevents the account from being reaped // Set the `keep_alive` parameter to `false` only if you are ok with the origin account being reaped let tx = sdk.tx.balances.transfer_all(dest, true); let res = tx.execute_and_watch_inclusion(&account, Options::default()).await?; println!( "Block Hash: {:?}, Block Number: {}, Tx Hash: {:?}, Tx Index: {}", res.block_hash, res.block_number, res.tx_hash, res.tx_index ); Ok(()) } // Add a main function to call transfer_all #[tokio::main] async fn main() { if let Err(e) = transfer_all().await { eprintln!("Error: {:?}", e); } } ``` 2. Run the code using: ```bash filename="terminal" name="cmd18" cargo run ``` #### avail-go 1. Inside `main.go`, add the following code: ```go showLineNumbers filename="avail-go" name="cmd19" package main import ( "fmt" "log" "os" "github.com/availproject/avail-go-sdk/primitives" SDK "github.com/availproject/avail-go-sdk/sdk" "github.com/joho/godotenv" ) func main() { // Load environment variables from .env file err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Make sure the SEED environment variable is set seed := os.Getenv("SEED") if seed == "" { log.Fatal("SEED environment variable is not set") } // Create an account from the SEED environment variable acc, err := SDK.Account.NewKeyPair(seed) if err != nil { log.Fatalf("Failed to create account: %v", err) } fmt.Println("Your account Address: " + acc.SS58Address(42)) // Initialize an SDK instance sdk, err := SDK.NewSDK("https://turing-rpc.avail.so/rpc") if err != nil { log.Fatalf("Failed to initialize SDK: %v", err) } // Convert the hex string to a MultiAddress destAddress, err := primitives.NewAccountIdFromAddress("5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk") if err != nil { log.Fatalf("Failed to convert address: %v", err) } dest := destAddress.ToMultiAddress() // Set to false if you don't want to keep the account alive keepAlive := true // Transferring all funds tx := sdk.Tx.Balances.TransferAll(dest, keepAlive) // Execute the transaction res, err := tx.ExecuteAndWatchInclusion(acc, SDK.NewTransactionOptions()) if err != nil { log.Fatalf("Transaction failed: %v", err) } // Check if the transaction was successful if !res.IsSuccessful().UnsafeUnwrap() { log.Fatal("Transaction was not successful") } fmt.Println("Transaction successful") // Printing out all the values of the transaction fmt.Println(fmt.Sprintf(`Block Hash: %v, Block Index: %v, Tx Hash: %v, Tx Index: %v`, res.BlockHash.ToHexWith0x(), res.BlockNumber, res.TxHash.ToHexWith0x(), res.TxIndex)) } ``` 2. Run the code using: ```bash filename="terminal" name="cmd20" go run main.go ``` > **Note** > > If you receive errors related to missing dependencies while trying to execute your code, run: > > ```bash filename="terminal" name="cmd21" > go mod tidy > ``` > > and try again. #### AvailApps explorer > **Note** > > Follow the same steps as before to use this extrinsic from the AvailApps explorer. > The only difference being that: > > 1. You need to select `balances_transferAll` from the dropdown. > 2. You don't need to fill in an `amount` that you want to transfer, since this extrinsic transfers all funds from the sender's account. Your response should look something like this:
Sample Response: ``` From=5CqgQkrDcdg5QrtuxT3H7WszrqgrBMhdwRbmMVXQzc4VSiEg, To=5DDY2yzh8uCysYFAiRSTeQVwtZSKNF49CkQkyPH852xvrYKk, Amount=14967497534555492726990 TxHash=0x3dbf0865aae15137e1fe3f922d70b7ff514a8c27e712d12ea1a8a1d4a7af9437, BlockHash=0x129745d18065f66f106b3744fe73ab5f9a1d7cb6205b271d13119399d3a56d31 ```
> If you check the balance of the sender account now, it will either be `0` or equal to the `existential deposit` amount, if > the account is unable to be reaped due to dependencies on the network. > In this case, while the account will continue to exist on the state trie, it's balance will be too low to perform any operations. ### Arbitrum Nitro stack - [**Overview**](/docs/da/build/rollups/arbitrum-nitro/overview) - [**[GUIDE] Deploy an Avail-Powered Orbit chain**](/docs/da/build/rollups/arbitrum-nitro/guide) ### Polygon CDK - [**Deploy a Polygon cdk Validium with Avail DA**](/docs/da/build/rollups/cdk/guide) ### Cosmos Avail DA module ## What is CADA (Cosmos Avail DA module) CADA is a module designed to connect Cosmos sovereign chains with the Avail network, making it easier for any Cosmos chain or rollapp to use Avail as their Data Availability (DA) layer. With CADA, developers can improve the scalability and security of their decentralized applications within the Cosmos ecosystem. It enables better data handling and availability, allowing Cosmos-based chains to tap into the strengths of Avail and build a more connected and resilient blockchain network. Learn more about the CADA module below: - [**Cosmos Avail DA Module**](https://github.com/vitwit/avail-da-module) ## What is Avail DA? Avail is the permisionless unification layer for web3. Avail is designed to be a platform that connects different ecosystems by providing a modular, scalable, and interoperable platform. Avail's vision is to provide a cohesive, unified user experience within a flexible and modular blockchain ecosystem, drawing on lessons from Web2 to innovate in Web3. With Avail's foundational DA layer ([Avail DA](/docs/da/get-started)), different ecosystems can innovate on top freely, while leveraging Nexus for cross-ecosystem messaging. Learn more about [Avail here](/docs/da/get-started). ## Integration Guide To integrate the CADA module into your Cosmos SDK application, follow the steps outlined in the [integration guide](https://github.com/vitwit/cada/tree/main/x/cada/integration_docs) > **Note** > > Note: Ensure that the Avail light client URL is correctly configured for the module to function as expected. For instructions on setup Avail locally, please refer to [this documentation](https://github.com/rollkit/avail-da?tab=readme-ov-file#avail-da). You can also use the references below for integration.You can also simply run the module from these repositories as well: - [**Cosmos SDK Integration Example**](https://github.com/vitwit/cosmos-sdk/tree/integrate_avail_da) - [**Avail DA Module with Simapp**](https://github.com/vitwit/avail-da-module/tree/main/simapp) If you are running the chain from the Simapp repository, you can use this [init-chain script](https://github.com/vitwit/avail-da-module/blob/main/simapp/init-simapp.sh) to set up the testnet. ## How It Works ### CADA (Cosmos Chain) Initiates the process by running the `PreBlocker ABCI` method. ### Request to Relayer Sends `block range` information to the relayer. ### Relayer Fetches the `block data` from the Cosmos Provider and posts it to the Avail light client. ### Avail light client Confirms whether the data is available. If **Yes**: Broadcast the Avail height and status. If **No**: Retry data submission. ### Validators Vote to confirm the data availability, updating the blob status to "Success" or "Failure" based on results. These are main components in the workflow: ### 1. CADA The core functionality of the **CADA** module is integrated with and operates on the Cosmos blockchain. In the CADA module: * At each block interval, the `PreBlocker` ABCI method sends a request to the `Relayer`, specifying the range of block heights that are ready to be posted to the **Avail** Data Availability (DA) network. Block Data Flow * The chain is responsible for aggregating vote extensions from all validators and verifying whether the data has been made available on Avail. * Since verification requires communicating with the light client, an asynchronous voting mechanism is needed. **Vote extensions** enable this asynchronous voting mechanism for verification purposes. Vote Extension ### 2. Relayer The **Relayer** facilitates communication between the Cosmos Chain, the Avail light client, and the Cosmos Provider. * **Data Submission**: The relayer is responsible for fetching block data from the Cosmos provider and posting it to the Avail light client via an HTTP request. * Based on the response from the light client, the relayer submits a transaction informing the validators of the data availability status and the specific Avail block height where the data is included, so that validators can verify it. * **Data Verification**: During verification, the relayer communicates with the Avail light client to confirm whether the data is truly available at the specified height. ### 3. Avail Light Node The **Avail light client** allows interaction with the Avail DA network without requiring a full node, and without having to trust remote peers. It leverages **Data Availability Sampling (DAS)**, which the light client performs on every newly created block. * The chain communicates with the Avail light client via the relayer during the data submission and data availability verification processes. Find more details about the Avail light client [here](/docs/da/operate/run-a-light-client/overview). ### 4. Cosmos Provider The **Cosmos Provider** is responsible for fetching block data via RPC so that the data can be posted to Avail for availability checks. ## Workflow * At each block interval, a request is sent from the `PreBlocker` ABCI method to the Keeper, specifying the range of block heights that are ready to be posted to the `Avail` DA network. * The range of block heights should be from `provenHeight + 1` to `min(provenHeight + MaxBlocksLimitForBlob, CurrentBlockHeight)`. * If the status of the previous blocks is either `SUCCESS` or `FAILURE`, the status can be updated to `PENDING`. ``` range = [fromBlock, toBlock] // (fromBlock < toBlock < CurrentBlock) status = PENDING ``` * The `Proposer` of the block will make a request to the `Relayer` to post the blocks data by passing the range of blocks to be posted. * The `Relayer` fetches the blocks data from the local provider, converts the blocks data to bytes, and posts that data to `Avail`. * Once the success of data availability is confirmed, the `Relayer` broadcasts the `Avail height` at which the blob data is made available using the `MsgUpdateBlobStatus` transaction. * The status, Avail height, and voting deadline will be updated in the state. ``` status = IN_VOTING availHeight = tx.availHeight votingEndBlock = currentBlock + votingInterval ``` * At block height `VotingEndBlock - 1`, all the validators verify if the specified blocks data is truly made available at the specified Avail height. They cast their vote (YES or NO) using `vote extensions`. * At block height `VotingEndBlock`, all the votes from `vote_extensions` will be collected and aggregated. If the collective `voting power is > 66%`, the status will be updated ``` status = SUCCESS // success and ready for next blocks provenHeight = Range EndHeight // End Height from the given block range ``` * In case of failure at any stage, the whole flow will be repeated. *** image: "/img/docs-link-preview\.png" ### Madara Starknet - [**Overview**](/docs/da/build/rollups/madara/overview) - [**Avail-Powered Madara Validium**](/docs/da/build/rollups/madara/guide) - [**Madara Starknet**](https://github.com/madara-alliance/madara) ### OP Stack ## What is the OP Stack? The OP Stack is the standardized, shared, and open-source development stack that powers Optimism, maintained by the Optimism Collective. The OP Stack is the set of software that powers Optimism — currently in the form of the software behind OP Mainnet and eventually in the form of the Optimism Superchain and its governance. The OP Stack is primarily focused around the creation of a shared, high-quality, and fully open-source system for creating new L2 blockchains. Learn more about the [OP Stack here](https://docs.optimism.io/stack/getting-started). ## What is Avail DA? Avail is the permisionless unification layer for web3. Avail is designed to be a platform that connects different ecosystems by providing a modular, scalable, and interoperable platform. Avail's vision is to provide a cohesive, unified user experience within a flexible and modular blockchain ecosystem, drawing on lessons from Web2 to innovate in Web3. With Avail's foundational DA layer ([Avail DA](/docs/da/get-started)), different ecosystems can innovate on top freely, while leveraging Nexus for cross-ecosystem messaging. Learn more about [Avail here](/docs/da/get-started). ## How does OP Stack work with Avail? The OP stack has become a popular choice for communities and companies looking to build their own L2 rollups. t’s used by OP Mainnet and is maintained by the Optimism Collective. It’s also a stack which developers have begun to extend and modify. One such modification is using a purpose-built data availability layer like Avail. The default DA layer supported by the OP stack is Ethereum. L2 transactions get submitted to the sequencer which is responsible for ordering transactions and creating L2 blocks. Batches of transactions are sent by the sequencer to Ethereum which submits transaction data as calldata. The Avail team built the Avail's OP Stack integrations which is allows L2s that are built using the integration to send transaction data to Avail instead of Ethereum, lowering transaction fees by up to 90%. Transactions are submitted to the sequencer node in the Avail OP Stack. The op-batcher then submits a transaction batch to a module called op-avail that has been added to submit data to Avail. The transaction data is then added to the Avail blockchain and a transaction reference is returned to op-avail which is passed to the op-batcher and submitted to Ethereum as calldata/blobs. The transaction reference posted on Ethereum contains the Avail block hash, sender’s address and nonce of the extrinsic. Chains built with the Avail OP Stack inherit the security guarantees of Avail’s nominated proof-of-stake blockchain network. Get started with building your Avail-powered OP Stack chain today. - [**Transaction Lifecycle**](/docs/da/build/rollups/op-stack/overview) - [**Avail-Powered Optimium (OP Stack)**](/docs/da/build/rollups/op-stack/guide) - [**OP Stack Adapter**](https://github.com/availproject/avail-op-stack-adapter) ### Polygon zkEVM - [**Overview**](/docs/da/build/rollups/zkevm/overview) - [**Avail-Powered zkEVM Validium**](/docs/da/build/rollups/zkevm/guide) - [**Validium Node**](https://github.com/availproject/validium-node) - [**Validium Contracts**](https://github.com/availproject/validium-contracts) - [**Validium Bridge**](https://github.com/availproject/validium-bridge-service) ### ZKsync's ZK Stack - [**Deploy an Avail-powered ZK Stack Validium**](/docs/da/build/rollups/zksync/guide) ### How to Backup Your Avail Validator ## Understanding Validator Directories Before diving into backup procedures, it's crucial to understand the directory structure of your Avail node. ### Directory Structure The Avail node's directory structure is as follows: ``` └── chains └── da_testnet └── db └── keystore └── network ``` ### Directory Descriptions * **db**: This directory contains the database files, which store blockchain state, transaction history, and other data. * **keystore**: This is where the encrypted key files for your Validator are stored. * **network**: This directory contains configuration files related to network connectivity and peer management. You can specify a custom directory using the `--base-path` parameter. ## Step 1: Re-Sync or Restore Snapshot ### To Re-Sync from Genesis Run the following command: ```bash avail purge-chain ``` ### To Restore a Database Snapshot 1. Stop your node. 2. Delete existing chain data. 3. Download a snapshot from another node. 4. Restore the snapshot to the `db` folder. > **Note** > > WARP SYNC > Warp sync will be available in future releases, allowing quicker node setup. ## Step 2: Backup Keystore ### To Move Keystore to a Backup Node 1. Ensure the primary node is offline. 2. Transfer the keystore to a backup node that is in sync. > **Error** > > EQUIVIVOCAITON RISK > Never run two nodes with identical keys at the same time to avoid double-signing. This method is not recommended for routine transitions between nodes. For safer alternatives, consult the [Upgrading Guide](/docs/da/operate/become-a-validator/upgrade-your-validator). ### Avail Node - Basics ## Introduction The goal of this guide is to help you learn the basics of running Avail Node. Don't worry; it's not too complicated, and it won't take you longer than 5 minutes to get a good grasp of how everything works. > **Note** > > BEFORE YOU START > All the guides, including this one, assume that you are using a Linux or macOS-based system. If you are running Windows and want to follow this guide, make sure to install WSL and continue the guide inside an Ubuntu or Debian instance. To learn more about WSL, check the following [LINK](https://learn.microsoft.com/en-us/windows/wsl/install). > **Note** > > NOTE > Before trying anything, make sure that you fully read the chapter first before doing any actual work. ## Installation & Setup Our first step is to obtain the prebuilt binary for Avail Node. [We offer a wide range of prebuilds](https://github.com/availproject/avail/releases), but in case you don't see your Linux flavor or architecture here, head to the FAQ chapter to learn how to build your own executable. Once you have found your OS (or picked the generic one), execute the given command to obtain the needed Avail Node binary. ```bash wget https://github.com/availproject/avail/releases/download//.tar.gz && tar -xf ./.tar.gz ``` ## Running Our First Network With the binary ready in our working directory, it's time to run it and see what we get. ```bash ./avail-node ``` Output: ``` Error: Input("Please specify which chain you want to run, e.g. --chain mainnet") ``` Yikes, an error. This is okay; by default, our node doesn't know which chain (network) it should connect to. To fix this, we will provide one, but not the recommended one, not yet. Instead, we are going to run a development network: ```bash ./avail-node --chain dev ``` Output: ```bash 2023-11-27 16:26:31 Avail Node 2023-11-27 16:26:31 ✌️ version 2.1.4-9d88dbf7b4f 2023-11-27 16:26:31 ❤️ by Avail Project , 2017-2024 2023-11-27 16:26:31 📋 Chain specification: Avail Development Network 2023-11-27 16:26:31 🏷 Node name: cagey-owl-5997 2023-11-27 16:26:31 👤 Role: FULL 2023-11-27 16:26:31 💾 Database: RocksDb at /home/markopetrlic/.local/share/data-avail/chains/avail_development_network/db/full 2023-11-27 16:26:32 [0] 💸 generated 1 npos voters, 1 from validators and 0 nominators 2023-11-27 16:26:32 [0] 💸 generated 1 npos targets 2023-11-27 16:26:32 🔨 Initializing Genesis block/state (state: 0x11f1…3471, header-hash: 0xdb94…2e21) 2023-11-27 16:26:32 👴 Loading GRANDPA authority set from genesis on what appears to be first startup. 2023-11-27 16:26:32 👶 Creating empty BABE epoch changes on what appears to be first startup. 2023-11-27 16:26:32 🏷 Local node identity is: 12D3KooWSKgdEtRrdwWVFPoE3q6z8mzrD5nkQ14Z7ta3D7oTn99V 2023-11-27 16:26:32 Prometheus metrics extended with avail metrics 2023-11-27 16:26:32 💻 Operating system: linux 2023-11-27 16:26:32 💻 CPU architecture: x86_64 2023-11-27 16:26:32 💻 Target environment: gnu 2023-11-27 16:26:32 💻 CPU: 13th Gen Intel(R) Core(TM) i7-13700K 2023-11-27 16:26:32 💻 CPU cores: 16 2023-11-27 16:26:32 💻 Memory: 31863MB 2023-11-27 16:26:32 💻 Kernel: 6.5.12-300.fc39.x86_64 2023-11-27 16:26:32 💻 Linux distribution: Fedora Linux 39 (Workstation Edition) 2023-11-27 16:26:32 💻 Virtual machine: no 2023-11-27 16:26:32 📦 Highest known block at #0 2023-11-27 16:26:32 〽️ Prometheus exporter started at 127.0.0.1:9615 2023-11-27 16:26:32 Running JSON-RPC server: addr=127.0.0.1:9944, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"] 2023-11-27 16:26:32 🏁 CPU score: 1.65 GiBs 2023-11-27 16:26:32 🏁 Memory score: 22.64 GiBs 2023-11-27 16:26:32 🏁 Disk score (seq. writes): 2.16 GiBs 2023-11-27 16:26:32 🏁 Disk score (rand. writes): 733.69 MiBs 2023-11-27 16:26:37 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:26:42 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:26:47 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:26:52 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 ``` Okay, things are looking better now. No errors so far, but let's break it down for clarity. ### Understanding the logs ```bash 2023-11-27 16:26:31 Avail Node 2023-11-27 16:26:31 ✌️ version 1.8.3-6d8aff28012 2023-11-27 16:26:31 ❤️ by Anonymous, 2017-2023 2023-11-27 16:26:31 📋 Chain specification: Avail Development Network 2023-11-27 16:26:31 🏷 Node name: cagey-owl-5997 2023-11-27 16:26:31 👤 Role: FULL ``` The first, second, and fourth lines indicate that we're running Avail Node v1.8.3 with the Development chain—exactly what we wanted. The fifth line, `🏷 Node name: cagey-owl-5997`, shows our node name as `cagey-owl-5997`, which isn't ideal. We'll change that shortly. The last line, `👤 Role: FULL`, reveals that our node is in Full mode, meaning it can't produce blocks. We'll address that too. ### Changing Name To change our node's name, use the `--name` flag. Before proceeding, make sure to stop your node with `Ctrl-C`. Now, let's rerun it with a more appealing name: ```bash ./avail-node --chain dev --name KingMagnifico ``` Output: ```bash 2023-11-27 16:39:37 Avail Node 2023-11-27 16:39:37 ✌️ version 1.8.3-6d8aff28012 2023-11-27 16:39:37 ❤️ by Anonymous, 2017-2023 2023-11-27 16:39:37 📋 Chain specification: Avail Development Network 2023-11-27 16:39:37 🏷 Node name: KingMagnifico 2023-11-27 16:39:37 👤 Role: FULL ... ``` ### Changing from Full to Validator mode To run our node in validator mode, add the `--validator` flag along with the others. Without this mode, the node won't produce new blocks. Stop your node again with Ctrl+C and rerun it with the `--validator` flag:: ```bash ./avail-node --chain dev --name KingMagnifico --validator ``` Output: ```bash 2023-11-27 16:41:49 Avail Node 2023-11-27 16:41:49 ✌️ version 1.8.3-6d8aff28012 2023-11-27 16:41:49 ❤️ by Anonymous, 2017-2023 2023-11-27 16:41:49 📋 Chain specification: Avail Development Network 2023-11-27 16:41:49 🏷 Node name: KingMagnifico 2023-11-27 16:41:49 👤 Role: AUTHORITY ... ``` Now, instead of 'FULL,' it should say 'AUTHORITY,' indicating that our node is almost ready to produce blocks. ### Session Keys and Peers If we let our program run for a minute or two, we'll notice the same message being repeated: ```bash ... 2023-11-27 16:48:57 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 ``` Our node is operating in validator mode, but the network expects validator 'Alice' to be online. To enable block production, besides using the `--validator` flag, the node needs session keys for signing various parts of block production. Without these keys, the network can't identify the block producer, leaving us stuck at block 0. In the next chapter, we'll address how to generate your own session keys. For this development network, we can use the `--alice` flag, and it will automatically insert Alice's session keys. Let's stop our node again with Ctrl+C and rerun it with the `--alice` flag: ```bash ./avail-node --chain dev --name KingMagnifico --validator --alice ``` Output: ```bash ... 2023-11-27 16:57:10 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:15 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:20 🙌 Starting consensus session on top of parent 0xdb94358c6e772b68a9e23b0ecbea316e4245f4d67b140ae5ffb58709ba222e21 2023-11-27 16:57:20 🎁 Prepared block for proposing at 1 (53 ms) [hash: 0xe7562addc0f4c6a249f23c7696f1a033c8801e33b413440b7d6e45f14da24acf; parent_hash: 0xdb94…2e21; extrinsics (1): [0x5e8b…40ea] 2023-11-27 16:57:20 🔖 Pre-sealed block for proposal at 1. Hash now 0x65ff1a30292f68a8c93e59a96a769975cdeb0d18d13fed5a83f168d579190645, previously 0xe7562addc0f4c6a249f23c7696f1a033c8801e33b413440b7d6e45f14da24acf. 2023-11-27 16:57:20 👶 New epoch 0 launching at block 0x65ff…0645 (block slot 85055032 >= start slot 85055032). 2023-11-27 16:57:20 👶 Next epoch starts at slot 85055752 2023-11-27 16:57:20 ✨ Imported #1 (0x65ff…0645) 2023-11-27 16:57:20 💤 Idle (0 peers), best: #1 (0x65ff…0645), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:25 💤 Idle (0 peers), best: #1 (0x65ff…0645), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:25 ❌ Error while dialing /dns/telemetry.avail.tools/tcp/8001/x-parity-ws/%2Fsubmit: Custom { kind: Other, error: Timeout } 2023-11-27 16:57:30 💤 Idle (0 peers), best: #1 (0x65ff…0645), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:35 💤 Idle (0 peers), best: #1 (0x65ff…0645), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:40 🙌 Starting consensus session on top of parent 0x65ff1a30292f68a8c93e59a96a769975cdeb0d18d13fed5a83f168d579190645 2023-11-27 16:57:40 🎁 Prepared block for proposing at 2 (0 ms) [hash: 0xd8b30ca60b080fd49decae48c1ad291a7666f4a3c2287ad5e596565ab1331016; parent_hash: 0x65ff…0645; extrinsics (1): [0x007f…9c1a] 2023-11-27 16:57:40 🔖 Pre-sealed block for proposal at 2. Hash now 0xaa5b610cf99ea519025f4fb803c4e4d874ed8d4eae97045327d44c364bdaec4a, previously 0xd8b30ca60b080fd49decae48c1ad291a7666f4a3c2287ad5e596565ab1331016. 2023-11-27 16:57:40 ✨ Imported #2 (0xaa5b…ec4a) 2023-11-27 16:57:40 💤 Idle (0 peers), best: #2 (0xaa5b…ec4a), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:45 💤 Idle (0 peers), best: #2 (0xaa5b…ec4a), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:50 💤 Idle (0 peers), best: #2 (0xaa5b…ec4a), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:57:55 💤 Idle (0 peers), best: #2 (0xaa5b…ec4a), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:58:00 🙌 Starting consensus session on top of parent 0xaa5b610cf99ea519025f4fb803c4e4d874ed8d4eae97045327d44c364bdaec4a 2023-11-27 16:58:00 🎁 Prepared block for proposing at 3 (0 ms) [hash: 0xfae370e93725b66c3909186d9e8d37f28e3ca6ab4f42841cc811d113d98a9335; parent_hash: 0xaa5b…ec4a; extrinsics (1): [0x1e14…5a8e] 2023-11-27 16:58:00 🔖 Pre-sealed block for proposal at 3. Hash now 0x78914110e09581baf6d85c791d1bc9f66400bc6fae2db7ee6724706870689083, previously 0xfae370e93725b66c3909186d9e8d37f28e3ca6ab4f42841cc811d113d98a9335. 2023-11-27 16:58:00 ✨ Imported #3 (0x7891…9083) 2023-11-27 16:58:00 💤 Idle (0 peers), best: #3 (0x7891…9083), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 16:58:05 💤 Idle (0 peers), best: #3 (0x7891…9083), finalized #1 (0x65ff…0645), ⬇ 0 ⬆ 0 ``` Now, we are running our own development network and we are producing and finalizing blocks. If this doesn't work and you're still stuck at block zero, try adding `--force-authoring` along with the other flags. ### There Must Be A Simpler Way Although we've used several flags to run a development network, there's an easier way—use the `--dev` flag. This flag combines the following flags into one: `--chain=dev`, `--force-authoring`, `--alice`, `--tmp`, and `--rpc-cors=all`. The last two flags, `--tmp` and `--rpc-cors=all`, are new to us, and we'll discuss `--tmp` shortly. Stop the node again with Ctrl+C and rerun it with the `--dev` flag: ```bash ./avail-node --dev --name KingMagnifico ``` Output: ```bash ... 2023-11-27 17:05:11 👶 Starting BABE Authorship worker 2023-11-27 17:05:16 💤 Idle (0 peers), best: #0 (0xdb94…2e21), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 2023-11-27 17:05:20 🙌 Starting consensus session on top of parent 0xdb94358c6e772b68a9e23b0ecbea316e4245f4d67b140ae5ffb58709ba222e21 2023-11-27 17:05:20 🎁 Prepared block for proposing at 1 (53 ms) [hash: 0x14e7136f060633d6fe4c47e85deb3cc6617dd5b978ee32e504eb5c3f900808bf; parent_hash: 0xdb94…2e21; extrinsics (1): [0xf649…0401] 2023-11-27 17:05:20 🔖 Pre-sealed block for proposal at 1. Hash now 0xfb47a6c99e803ee10678440beeb9f870dfb9b807ef96f5172f1d02bf0c163e3e, previously 0x14e7136f060633d6fe4c47e85deb3cc6617dd5b978ee32e504eb5c3f900808bf. 2023-11-27 17:05:20 👶 New epoch 0 launching at block 0xfb47…3e3e (block slot 85055056 >= start slot 85055056). 2023-11-27 17:05:20 👶 Next epoch starts at slot 85055776 2023-11-27 17:05:20 ✨ Imported #1 (0xfb47…3e3e) 2023-11-27 17:05:21 💤 Idle (0 peers), best: #1 (0xfb47…3e3e), finalized #0 (0xdb94…2e21), ⬇ 0 ⬆ 0 ``` And we get the same result. ### Temporary and Persistent Storage When our node runs a network, it needs to store network-related data. By not specifying a location, it stores the data in a default location, which is often not what we want. Using the `--tmp` flag makes it use a different location each time we run our network. This is implied when using `--dev` and is useful when we don't care about preserving our state. To make our storage persistent through runs, we can use the `-d` flag. ```bash ./avail-node --dev --name KingMagnifico -d ./node-data ``` Output ```bash 2023-11-27 17:13:54 Avail Node 2023-11-27 17:13:54 ✌️ version 1.8.3-6d8aff28012 2023-11-27 17:13:54 ❤️ by Anonymous, 2017-2023 2023-11-27 17:13:54 📋 Chain specification: Avail Development Network 2023-11-27 17:13:54 🏷 Node name: KingMagnifico 2023-11-27 17:13:54 👤 Role: AUTHORITY 2023-11-27 17:13:54 💾 Database: RocksDb at ./node-data/chains/avail_development_network/db/full ``` In the logs (output), you'll notice our database is now located at `./node-data/chains/avail_development_network/db/full` instead of the `tmp` folder. Once the node is running, a new folder named `node-data` will be created in the working directory. If you take a look, you will see that it consists of subdirectories like `chains` and `avail_development_network`. Inside the last directory, you should find our network data. After running the node for a minute or two, stop it by pressing Ctrl+C and rerun it. It should use the same storage (database) location and continue from the last produced block. Now stop the node with Ctrl+C and let's remove our storage: `rm ./node-data -r`. ## Connecting Our Node to Turing With all this preliminary knowledge ready to be used, we can now finally take the last step and connect our node to the Turing network. I will use the same name as before, KingMagnifico, but I suggest you choose one that you like. Before running our node, ensure that our storage folder is removed or empty, and that we don't have any previous nodes already running. With that said, let's finally do what we've been waiting for since the beginning: ```bash ./avail-node --chain turing --name KingMagnifico --validator -d ./node-data ``` Output: ```bash 2023-11-27 17:24:41 Avail Node 2023-11-27 17:24:41 ✌️ version 1.8.3-6d8aff28012 2023-11-27 17:24:41 ❤️ by Anonymous, 2017-2023 2023-11-27 17:24:41 📋 Chain specification: Avail Turing Testnet 2023-11-27 17:24:41 🏷 Node name: KingMagnifico 2023-11-27 17:24:41 👤 Role: AUTHORITY 2023-11-27 17:24:41 💾 Database: RocksDb at ./node-data/chains/avail_turing_testnet/db/full ``` Okay, so far so good. Our role is `AUTHORITY`, which means that we are running in validator mode. Our name is clearly the correct one, KingMagnifico, and our database location is correct. Let's see the next few log lines: ```bash 2023-11-27 17:24:43 🔨 Initializing Genesis block/state (state: 0x6bc7…ec83, header-hash: 0x6f09…a7ae) 2023-11-27 17:24:43 👴 Loading GRANDPA authority set from genesis on what appears to be first startup. 2023-11-27 17:24:43 👶 Creating empty BABE epoch changes on what appears to be first startup. 2023-11-27 17:24:43 🏷 Local node identity is: 12D3KooWH5bTMnPJXnUqmGcVTX1fmG5ervReMTBFpFZdJNc9WW4u 2023-11-27 17:24:43 Prometheus metrics extended with avail metrics 2023-11-27 17:24:43 💻 Operating system: linux 2023-11-27 17:24:43 💻 CPU architecture: x86_64 2023-11-27 17:24:43 💻 Target environment: gnu 2023-11-27 17:24:43 💻 CPU: 13th Gen Intel(R) Core(TM) i7-13700K 2023-11-27 17:24:43 💻 CPU cores: 16 2023-11-27 17:24:43 💻 Memory: 31863MB 2023-11-27 17:24:43 💻 Kernel: 6.5.12-300.fc39.x86_64 2023-11-27 17:24:43 💻 Linux distribution: Fedora Linux 39 (Workstation Edition) 2023-11-27 17:24:43 💻 Virtual machine: no 2023-11-27 17:24:43 📦 Highest known block at #0 2023-11-27 17:24:43 〽️ Prometheus exporter started at 127.0.0.1:9615 2023-11-27 17:24:43 Running JSON-RPC server: addr=127.0.0.1:9944, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"] 2023-11-27 17:24:43 🏁 CPU score: 1.61 GiBs 2023-11-27 17:24:43 🏁 Memory score: 22.37 GiBs 2023-11-27 17:24:43 🏁 Disk score (seq. writes): 2.06 GiBs 2023-11-27 17:24:43 🏁 Disk score (rand. writes): 749.80 MiBs 2023-11-27 17:24:43 👶 Starting BABE Authorship worker 2023-11-27 17:24:44 🔍 Discovered new external address for our node: /ip4/176.61.156.176/tcp/30333/p2p/12D3KooWH5bTMnPJXnUqmGcVTX1fmG5ervReMTBFpFZdJNc9WW4u 2023-11-27 17:24:48 ⚙️ Syncing, target=#85251 (8 peers), best: #2685 (0x6fd4…975f), finalized #2560 (0x1282…a791), ⬇ 2.9MiB/s ⬆ 62.5kiB/s 2023-11-27 17:24:53 ⚙️ Syncing 63.0 bps, target=#85251 (8 peers), best: #3000 (0x8189…6cc7), finalized #2560 (0x1282…a791), ⬇ 108.2kiB/s ⬆ 5.5kiB/s ``` Nothing that we haven't seen before, except for the last two lines. `⚙️ Syncing` means that we are syncing all the blocks that were already built, which is exactly what we wanted to see. Let's check the next few lines: ```bash 2023-11-27 17:24:57 [3241] 💸 generated 13 npos targets 2023-11-27 17:24:57 [3241] 💸 generated 22 npos voters, 13 from validators and 9 nominators 2023-11-27 17:24:57 [#3241] 🗳 creating a snapshot with metadata SolutionOrSnapshotSize { voters: 22, targets: 13 } 2023-11-27 17:24:57 [#3241] 🗳 Starting phase Signed, round 1. 2023-11-27 17:24:58 ⚙️ Syncing 61.0 bps, target=#85251 (8 peers), best: #3305 (0xc752…f70e), finalized #3072 (0x1231…8aad), ⬇ 113.8kiB/s ⬆ 0.9kiB/s 2023-11-27 17:25:00 [#3421] 🗳 Starting phase Unsigned((true, 3421)), round 1. 2023-11-27 17:25:00 [#3422] 🗳 queued unsigned solution with score ElectionScore { minimal_stake: 56800545104270, sum_stake: 284279432410424, sum_stake_squared: 16163020265485588884279726278 } 2023-11-27 17:25:02 [#3601] 🗳 Starting phase Off, round 2. 2023-11-27 17:25:02 [3601] 💸 new validator set of size 5 has been processed for era 1 2023-11-27 17:25:03 ⚙️ Syncing 174.0 bps, target=#85252 (8 peers), best: #4175 (0x4e80…5022), finalized #4096 (0xa3c0…c108), ⬇ 218.9kiB/s ⬆ 3.1kiB/s 2023-11-27 17:25:08 ⚙️ Syncing 86.6 bps, target=#85252 (8 peers), best: #4608 (0x1783…e94d), finalized #4321 (0xc708…7dc1), ⬇ 60.8kiB/s ⬆ 0.3kiB/s 2023-11-27 17:25:13 ⚙️ Syncing 194.6 bps, target=#85252 (8 peers), best: #5581 (0x5349…c169), finalized #5120 (0x065c…2a2f), ⬇ 94.7kiB/s ⬆ 0.6kiB/s 2023-11-27 17:25:17 [7561] 💸 generated 35 npos targets 2023-11-27 17:25:17 [7561] 💸 generated 64 npos voters, 35 from validators and 29 nominators 2023-11-27 17:25:17 [#7561] 🗳 creating a snapshot with metadata SolutionOrSnapshotSize { voters: 64, targets: 35 } 2023-11-27 17:25:17 [#7561] 🗳 Starting phase Signed, round 2. 2023-11-27 17:25:18 [#7741] 🗳 Starting phase Unsigned((true, 7741)), round 2. 2023-11-27 17:25:18 [#7742] 🗳 queued unsigned solution with score ElectionScore { minimal_stake: 55937820931230, sum_stake: 581366796392448, sum_stake_squared: 33804612421896598810633033648 } 2023-11-27 17:25:18 [#7921] 🗳 Finalized election round with compute Unsigned. 2023-11-27 17:25:18 [#7921] 🗳 Starting phase Off, round 3. 2023-11-27 17:25:18 [7921] 💸 new validator set of size 10 has been processed for era 2 2023-11-27 17:25:18 ⚙️ Syncing 479.4 bps, target=#85252 (8 peers), best: #7978 (0x01f5…a562), finalized #7680 (0x0ba7…c3f5), ⬇ 302.9kiB/s ⬆ 3.8kiB/s 2023-11-27 17:25:23 ⚙️ Syncing 453.4 bps, target=#85253 (8 peers), best: #10245 (0xad17…4ded), finalized #10240 (0x13da…a4be), ⬇ 591.2kiB/s ⬆ 1.0kiB/s 2023-11-27 17:25:25 [11613] 💸 generated 35 npos targets 2023-11-27 17:25:25 [11613] 💸 generated 74 npos voters, 35 from validators and 39 nominators ``` It's syncing around 450 blocks per second—quite fast! If we leave it for 5 or 10 minutes, it should be done syncing, and this is what we are going to see: ```bash 2023-11-27 17:31:30 [84993] 💸 new validator set of size 185 has been processed for era 21 2023-11-27 17:31:33 ⚙️ Preparing 104.2 bps, target=#85271 (8 peers), best: #85232 (0x234e…a535), finalized #84992 (0x62c0…772a), ⬇ 54.7kiB/s ⬆ 0.9kiB/s 2023-11-27 17:31:38 💤 Idle (8 peers), best: #85271 (0xa69a…7366), finalized #85269 (0xe83c…64ba), ⬇ 46.8kiB/s ⬆ 1.6kiB/s 2023-11-27 17:31:40 ✨ Imported #85272 (0x0410…df45) 2023-11-27 17:31:43 💤 Idle (8 peers), best: #85272 (0x0410…df45), finalized #85270 (0x7604…006b), ⬇ 43.8kiB/s ⬆ 159.2kiB/s 2023-11-27 17:31:48 💤 Idle (8 peers), best: #85272 (0x0410…df45), finalized #85270 (0x7604…006b), ⬇ 87.2kiB/s ⬆ 209.8kiB/s ``` Once we see `💤 Idle`, we are done syncing, and our node has now fully caught up. ## What's Next This is where our story ends. We have a working node connected to the Turing chain. It doesn't do much right now, certainly doesn't produce any blocks, but this is something that we will fix. Before that, let's discuss in the next chapter how to do a simple but effective deployment. ### Chill Your Validator ## Overview Two important concepts in Avail consensus are "Chill" and "Slashing". We will explore the conditions under which validators are chilled or slashed, the impact of these actions on validators and nominators. ## Voluntary Chill Staking bonds can exist in three different states: validating, nominating, or chilled. Chilled which refers to neither validating nor nominating. If a staker wishes to temporarily pause their active involvement in staking while keeping their funds bonded, they have the option to "chill" their participation. To step back from active staking or active validating an account can either click "Stop" on the [Network > Staking > Account actions page](https://explorer.avail.so/#/staking/actions) in Avail Apps or make use of the chill extrinsic in the staking pallet. By choosing to chill, the account or validator becomes inactive in the next era. It's important to note that the chill call must be signed by the controller account, not the stash. If you decide to voluntarily chill as a validator, your nominators will remain associated with your validator. However, while you are chilled, your bond will not be listed as an option for nominators to select. This means that any nominators making new nominations or revising existing ones will not be able to choose your validator. ## Involuntary Chill In the event that a validator becomes unresponsive for an entire session, the validator bond will undergo involuntary chilling. This process restricts the validator from being chosen in the subsequent election, depending on the session in which the chilling occurred. However, a chilled validator has the ability to declare their intent to validate again at any time. If less than 10% of nodes go offline there is no slash for being unresponsive or offline. ### Slashing Involuntary chilling can also occur as a consequence of slashing. However, in such a situation, the validator not only loses their nominations but also faces a potential loss of support. Consequently, even if the validator re-declares their intent to validate before session 5, there may not be enough nominations to reintegrate the node into the active set. Nominators have the opportunity to renominate a slashed validator through a display row available in Avail Apps in the "Account Actions". Slashing can occur under the following conditions * Equivocation is producing two blocks in the same slot. In GRANDPA, it is sending pre-vote or pre-commit messages for two chains that conflict with each other in the same round. This will slash the validator and nominators. * If more than 10% of the validators go offline simultaneously and were chilled in an epoch, all of those validators will be slashed. The slashing will show immediately on [Avail Apps](https://explorer.avail.so/#/staking/slashes) on the slash tab. However the financial slash is not applied at the time. The physical deduction from validator stake and nominator stake happens at a later stage. A governance proposal can be made to reverse the slash, this is why there is a delay in the physical deduction of coins. Without Governance intervention the physical coin deduction will happen a few days later. Example of a slash shown in Avail Apps: ### Avail Node - Simple Deployment ## Introduction > **Note** > > **ASSISTED DEPLOYMENT** > If you prefer running your Avail validator with the help of an infrastructure provider, you can check out [on-finality's docs here](https://documentation.onfinality.io/support/set-up-an-avail-validator-with-onfinality). This guide aims to help you learn the basics of deploying your Avail Node manually or by docker/podman. ## Cloud Server Deploying long-lasting services is best done on an online machine more than 99% of the time and is dedicated solely to running that service. This means that your Avail Node should not be deployed on a personal computer; running it on your Homelab or a cloud provider is a better option. There are many cloud providers to choose from. Here are some of them: * AWS * Microsoft Azure * OVHCloud * DigitalOcean * Linode * Google Cloud Platform It's up to you to research and pick one that will suit all your needs and requirements. If you already have a running server, you can skip the rest of this section and go straight to the next one. That said, Latitude is used for this chapter and here are the steps on how to create a new instance there: 1. First, create a project and give it a name. 2. Click on the 'Create Server' button and choose your desired location and image. 3. Click on the 'Create Server' button and choose your desired location and image. We're using Ubuntu 24 for this guide. 4. For the server type, `c2.small.x86` , `s2.small.x86` , `c2.medium.x86` or anything stronger should do the trick. 5. Enter your SSH keys 6. Give your server a name. 7. Copy the IP and SSH of your server. 8. SSH into your server by running the following command in your terminal: ```bash # Replace the IP with your own ssh ubuntu@199.xxx.xxx.xxx ``` 9. If everything is set up correctly, you should see the welcome message: ## Bare Metal We have our server up and online. We updated all our dependencies and are ready to do the work. > **Note** > > **BEFORE WE BEGIN** > > While working with Linux distros, it is a good practice to update the package list and upgrade the system before undertaking > major operations. You can use this command to do so: > > ```bash > sudo apt update && sudo apt upgrade -y > ``` 1. Let's create a folder in the home directory to store our binary and all the data it will generate. ```bash mkdir avail && cd avail mkdir node-data ``` 2. Depending on the user and operating system used, the path to our newly created folder can be `/root/avail` or `/home/ubuntu/avail` or any other variant. To get the full path, run this:" ```bash pwd # Example output: `/root/avail` ``` 3. From the [Releases Page](https://github.com/availproject/avail/releases), we grab the latest version and unpack it. > **Warning** > > NODE VERSION FOR TURING > Please note that the Avail node underwent major breaking changes while making upgrades to transition towards Turing. ```bash # Obtaning Latest avail-node version for Ubuntu 22.04 # Put in the latest version in the command below # wget is a command-line utility for downloading files from the internet. wget https://github.com/availproject/avail/releases/download//x86_64-ubuntu-2204-avail-node.tar.gz # tar is a command-line utility for working with tarballs, compressed or uncompressed archives containing one or more files or directories. # The -x option extracts files from an archive, and the -f option specifies the archive file. When used together as tar -xf, it removes the contents of the specified archive file. tar -xf /root/avail/x86_64-ubuntu-2204-avail-node.tar.gz # rm stands for "remove" in Linux and Unix-like operating systems. It is used to delete files or directories. rm -xf x86_64-ubuntu-2204-avail-node.tar.gz ``` We will create a system service file for our node to run automatically, even on restarts. Systemd will run our node as a daemon and manage it for us. To know more about systemd, go [here](https://en.wikipedia.org/wiki/Systemd). 4. Create a seperate directory to store all your node data: ```bash mkdir node-data ``` 5. Let's create a file on `/etc/systemd/system/` and name it `avail.service`. If you are using a non-root user, you will need to execute this operation using the `sudo` command. For root users: ```bash touch /etc/systemd/system/avail.service ``` For non-root users: ```bash sudo touch /etc/systemd/system/avail.service ``` 6. Now open that file with your favorite text editor. If this is your first time using Linux first learn how to use [nano](https://www.howtogeek.com/42980/the-beginners-guide-to-nano-the-linux-command-line-text-editor/) before doing anything. Just like before, if you are on a non-root use you might need to execute the command using 'sudo'. For root users: ```bash # Use nano or any other text editor like vim or emacs nano /etc/systemd/system/avail.service ``` For non-root users: ```bash # Use nano or any other text editor like vim or emacs sudo nano /etc/systemd/system/avail.service ``` 7. Paste the following text and save it: ```ini [Unit] Description=Avail Node [Service] Type=simple ExecStart=/root/avail/avail-node --chain mainnet --name {your-name-here} --validator -d /avail/node-data Restart=always RestartSec=3 StandardOutput=syslog StandardError=syslog SyslogIdentifier=avail-node [Install] WantedBy=multi-user.target ``` Let's let's break it down for clarity. * **Description**: Provides a human-readable description of the service. In this case, it describes the service as "Avail Node". This description is mainly used for documentation purposes and can be displayed in various system management tools and commands. * **ExecStart**: Specifies the command to start the service. In this case, it runs the /root/avail/data-avail executable with a series of command-line arguments. * **Restart**: Defines the restart behavior of the service. In this case, the service will be restarted if it fails. * **RestartSec**: Specifies the time to sleep before restarting the service after it exits unexpectedly. In this case, it's set to 5 seconds. * **WantedBy**: Specifies the target or targets that this service should be included in. Here, it is set to multi-user.target, which is a common target for services that should be started in a multi-user system. We discussed what the command line arguments do in the [previous chapter](/docs/da/operate/become-a-validator/basics), so we won't repeat ourselves here. 8. Now, let's enable the service file and start our deamon For root users: ```bash systemctl daemon-reload systemctl start avail.service systemctl enable avail.service ``` For non-root users: ```bash sudo systemctl daemon-reload sudo systemctl start avail.service sudo systemctl enable avail.service ``` 9. You can check the status of your node by: ```bash systemctl status avail.service ``` 10. To check for logs, we can run the following command: ```bash # -f Follow the journal # -n Number of journal entries to show # -u Show logs from the specified unit journalctl -f -n 1000 -u avail.service ``` or ```bash journalctl -u avail.service ``` Output ```bash ... Nov 29 14:56:23 MyAwesomeAvailServer data-avail[13040]: 2023-11-29 14:56:23 ⚙️ Syncing 135.7 bps, target=#93564 (11 peers), best: #1475 (0x1fe8…9dc7), finalized #1024 (0xdff3…8159), ⬇ 1.4MiB/s ⬆ 26.5kiB/s Nov 29 14:56:28 MyAwesomeAvailServer data-avail[13040]: 2023-11-29 14:56:28 ⚙️ Syncing 144.5 bps, target=#93564 (11 peers), best: #2198 (0xef82…72af), finalized #2048 (0xd68a…5cfc), ⬇ 150.0kiB/s ⬆ 3.7kiB/s Nov 29 14:56:33 MyAwesomeAvailServer data-avail[13040]: 2023-11-29 14:56:33 ⚙️ Syncing 92.8 bps, target=#93564 (12 peers), best: #2662 (0xdb75…7806), finalized #2560 (0x1282…a791), ⬇ 821.7kiB/s ⬆ 2.6kiB/s ``` As expected, the node is syncing new blocks. If these logs are new to you, head back to the [previous chapter](/docs/da/operate/become-a-validator/basics) where we explained in detail what they mean. ## Docker/Podman We have our server up and online. We updated all our dependencies and are now ready to do the actual work. 1. In the home directory, let's create a folder where we are going to store all the data that the Avail Docker container will generate. ```bash mkdir avail && cd avail mkdir node-data ``` Depending on the user and operating system used, the path to our newly created folder can be `/root/avail` or `/home/ubuntu/avail` or any other variant. 2. To get the full path, run this:" ```bash pwd # Example output: `/root/avail` ``` 3. Depending on your preferences, install Docker or Podman (or both) and execute one of the commands below. Don't execute all of them. To read more about Docker, check the [following page](https://www.docker.com/). To read more about Podman, check the [following page](https://podman.io/). To read more about SELinux, check the [following page](https://www.redhat.com/en/topics/linux/what-is-selinux). ```bash # Option 1: If you are using Docker with non-root user use this script sudo docker run --restart=on-failure -d -v /root/avail/node-data:/da/node-data -p 9944:9944 -p 30333:30333 docker.io/availj/avail:v1.8.0.3 --chain mainnet -d /da/node-data --validator --name MyAwesomeContainerNode # Option 2: If you are using Docker on SELinux use this script docker run --restart=on-failure -d -v /root/avail/node-data:/da/node-data:z -p 9944 -p 30333 docker.io/availj/avail:v1.8.0.3 --chain mainnet -d /da/node-data --validator --name MyAwesomeContainerNode # Option 3: If you are using Podman use this script podman run -d -v /root/avail/node-data:/da/node-data -p 9944 -p 30333 docker.io/availj/avail:v1.8.0.3 --chain mainnet -d /da/node-data --validator --name MyAwesomeContainerNode # Option 4: If you are using Podman on SELinux use this script podman run -d -v /root/avail/node-data:/da/node-data:z -p 9944 -p 30333 docker.io/availj/avail:v1.8.0.3 --chain mainnet -d /da/node-data --validator --name MyAwesomeContainerNode ``` > **Note** > > Make sure that you replace `/root/avail/node-data` with your own storage path. If your node-data is located in `/home/ubuntu/avail/node-data` than the flag should look like this: > `-v /home/ubuntu/avail/node-data:/da/node-data`. Let's break it down for clarity. * **--restart on-failure**: It means that the container will be automatically restarted if it exits with a non-zero status, indicating a failure. * **-d**: It means that the container will be automatically restarted if it exits with a non-zero status, indicating a failure. * **-v**: Is used to mount a volume in a Docker container. Volumes in Docker provide a way to persist and share data between a Docker container and the host system or between different containers. * **-p**: is used to publish a container's port to the host. It allows you to map a port from the container to a port on the host, making services running inside the container accessible from outside. * **docker.io/availj/avail:v1.8.0.3**: Refers to the name of the Docker image from which you want to create a container. A Docker image is a lightweight, stand-alone, executable package that includes everything needed to run a piece of software, including the code, a runtime, libraries, environment variables, and config files. We discussed what the command line arguments do in the [previous chapter](/docs/da/operate/become-a-validator/basics), so we won't repeat ourselves here. > **Note** > > Podman doesn't have the `--restart` flag, instead it utilizes Quadlets. To know more about how to setup a Quadlet following [this link](https://www.redhat.com/sysadmin/quadlet-podman) 4. To check for logs, we can run the following command: ```bash # Option 1: If you are using Docker with root user use this script docker logs -f $(docker ps -lq) # Option 2: If you are using Docker with non-root user use this script sudo docker logs -f $(docker ps -lq) # Option 3: If you are using Podman use this script podman logs -lf ``` Output ```bash 2023-11-29 22:54:56 ⚙️ Syncing 197.6 bps, target=#94986 (8 peers), best: #4363 (0x5374…0cc4), finalized #4321 (0xc708…7dc1), ⬇ 338.7kiB/s ⬆ 2.9kiB/s 2023-11-29 22:55:01 ⚙️ Syncing 62.0 bps, target=#94987 (8 peers), best: #4673 (0x7495…e6ea), finalized #4608 (0x1783…e94d), ⬇ 14.4kiB/s ⬆ 0.3kiB/s 2023-11-29 22:55:06 ⚙️ Syncing 225.4 bps, target=#94987 (8 peers), best: #5800 (0xbc68…13e8), finalized #5632 (0x5180…98c8), ⬇ 129.3kiB/s ⬆ 0.8kiB/s ``` As expected, the node is syncing new blocks. If these logs are new to you, head back to the [previous chapter](/docs/da/operate/become-a-validator/basics) where we explained in detail what they mean. ## What's Next This is where our story ends. We have a working node connected to the Turing chain and deployed on a cloud provider. If the system restarts or the Avail Node program suddenly ends, it will be automatically restarted, so there will be almost no downtime. ### How to Monitor Your Avail Validator Node ## Telemetry Maintaining a healthy, stable, and secure ecosystem involves closely monitoring network operations and performance. In the case of Avail nodes, they come equipped with built-in low-level telemetry components that automatically gather and transmit detailed information about each node's operation within the network. This backend telemetry data is streamed in real-time to a designated endpoint, allowing you to observe information regarding your nodes behavior. Avail project has made available a [public telemetry](http://telemetry.avail.so/) for anyone to view the status of their nodes. This should not replace your own monitoring and alerts. However it is a key tool that anyone can use to view the status of their nodes at anytime. Avail telemetry has been added to the chain specification file and should automatically send telemetry data to Avail [public telemetry](http://telemetry.avail.so/). You can however also add the telemetry `--telemetry-url 'ws://telemetry.avail.so:8001/submit/ 0'` to your avail node start command if your node is not visible on the public telemetry. You can also use `--name ` to set the name that will display on telemetry. Without this it will display a random node name on the telemetry. For example: ``` ./data-avail --validator \ --port 30333 \ --base-path `pwd`/data \ --chain `pwd`/chainspec.raw.json \ --name AvailNode \ --telemetry-url 'ws://telemetry.avail.tools:8001/submit/ 0' ``` ## Monitoring with Prometheus & Grafana Prometheus serves as a monitoring platform that gathers metrics from monitored targets through scraping their metrics HTTP endpoints. In contrast, Grafana acts as a visualization dashboard specifically designed to present the collected data in an easily understandable and visually appealing manner. The below guide is for setting up a local Prometheus & Grafana instance on the same server as your Avail node. If you're already experienced with Prometheus & Grafana and want to connect your Avail node to an existing Prometheus installation on a different server, include the `--prometheus-external` flag in your Avail node's startup command. ### Install Prometheus Install prometheus and prometheus node exporter. ``` sudo apt-get install -y prometheus prometheus-node-exporter ``` Create the prometheus.yml config file ``` cat > $HOME/prometheus.yml << EOF global: scrape_interval: 15s evaluation_interval: 15s rule_files: # - "first.rules" # - "second.rules" scrape_configs: - job_name: "prometheus" scrape_interval: 5s static_configs: - targets: ["localhost:9090"] - job_name: "avail_node" scrape_interval: 5s static_configs: - targets: ["localhost:9615"] - job_name: node static_configs: - targets: ['localhost:9100'] EOF ``` Move `prometheus.yml` to the correct location ``` sudo mv $HOME/prometheus.yml /etc/prometheus/prometheus.yml ``` Update the file permissions ``` sudo chmod 644 /etc/prometheus/prometheus.yml ``` Ensure Prometheus starts automatically ``` sudo systemctl enable prometheus.service prometheus-node-exporter.service ``` Restart Prometheus to activate latest settings ``` sudo systemctl restart prometheus.service prometheus-node-exporter.service ``` Check the status, ensure Prometheus has started without errors ``` sudo systemctl status prometheus.service prometheus-node-exporter.service ``` ### Install Grafana Install Grafana ``` wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add - echo "deb https://packages.grafana.com/oss/deb stable main" > grafana.list sudo mv grafana.list /etc/apt/sources.list.d/grafana.list sudo apt-get update && sudo apt-get install -y grafana ``` Ensure Grafana starts automatically ``` sudo systemctl enable grafana-server.service ``` Start Grafana ``` sudo systemctl start grafana-server.service ``` Check the status, ensure Grafana has started without errors ``` sudo systemctl status grafana-server.service ``` ### Setup Grafana Dashboard Ensure port 3000 is open, example of adding to ubuntu firewall ``` sudo ufw allow 3000/tcp ``` In your browser navigate to `http://:3000`. The default login username and password is admin/admin You will be asked to reset your password, please write it down or remember the password as you will need it for the next login. You will need to create a datasource. Navigate to **Home->Connections->Data sources** Click on **Add data source** Click on **Prometheus** Set URL to "localhost:9090", then test and save the connection Navigate back to your home page, on the top right in the menu select **Import dashboard** Import the [Avail Node Metrics file](https://raw.githubusercontent.com/availproject/docs/main/static/validator_metrics.json) You will have a new dashboard that opens and that you can use to monitor your node ### Avail Node - Session Keys ## Introduction > **Note** > > BEFORE YOU START > This chapter continues from the 'Simple Deployment' page, so be sure to read that one before proceeding with this one. > **Note** > > NOTE > Before trying anything, make sure that you fully read the chapter first before doing any actual work. With our infrastructure set up and our node running, we are ready to register ourselves as potential future validators. If the need for on-chain registration to become a validator seems foreign to you, then this would be a perfect opportunity to do your own research about how Proof of Stake and Nominated Proof Of Stake works. In short, to prevent people from running faulty validators and earning tokens, all validators need to bond a certain amount of tokens to register and be eligible for the position of producing blocks. With that mechanism in place, all validators that are in some way faulty will either be deregistered or, in the worst case, slashed. This explanation only covers the surface of how the whole system works, and before continuing, make sure that you do your own research and learn how the system actually operates. A good place to start is to read [Polkadot's explanation](https://wiki.polkadot.network/docs/learn-staking) on how it works. ## Session Keys Before we can bond our tokens we need to generate our session keys. In simpler terms, session keys in Substrate are like special secret codes that uniquely identify who's in charge of creating and validating blocks in a blockchain. Each participant, known as a validator, has their own secret key. They use these keys to sign off on the blocks they create, sort of like a personalized signature. This helps make sure everyone knows who's responsible for what, and it adds a layer of security to the whole blockchain process. So, we can think of session keys as the blockchain's way of keeping track of who did what in a trustworthy and secure manner. To generate it, we can the following command inside the server that is running our node: ### Bare Metal: ```bash # Generate session keys curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "author_rotateKeys", "params":[]}' http://localhost:9944 # Restart our Node sudo systemctl restart avail.service ``` ### Docker/ Podman ```bash # First let's ssh into our container # Option 1: Docker non-root sudo docker exec -it $(docker ps -lq) /bin/bash # Option 2: Podman podman exec -lit /bin/bash # Generate the Session keys curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "author_rotateKeys", "params":[]}' http://localhost:9944 # Exit and restart containe exit # Option 1: Docker non-root sudo docker restart $(docker ps -lq) # Option 2: Podman podman restart -l ``` > **Note** > > NOTE > If you encounter the following error inside the container: `bash: curl: command not found`, make sure to first install `curl` inside the container and then retry it. > For Ubuntu, you can run `apt install curl -y` for root or `sudo apt install curl -y` for non-root user to have it installed ### Output Running the curl command either bare metal or inside a container should yield the same result. The command generated the session keys for us, stored them inside our node-related-data folder, and displayed it for us. This key is unique to your own node, so it's important to make sure that it is stored safely and never shared with anyone. Example Output ```json { "jsonrpc": "2.0", "result": "0x0c26b9ba4b8fb5f3051a24663ce491663d8e8e81e8f1450ab23e4edd7d3b4f4c7e5e1047ae1edAb5bde2dad7915629b8aec892c550515ed0b1cb7e056e8a33d16c9c7faba50abd75438d4a2bbdbb6b2c35e09ad480e07ffeb1a2175feda23a3fd475eb0ad21e2f67693a1d6964b81d1454a19dd53256223a178a74cb0df4cc43", "id": 1 } ``` ### How to Stake Your Validator This guide offers a step-by-step walkthrough on how to stake your Avail validator. It covers essential steps such as bonding your funds, managing session keys, and initiating the validation process. > **Note** > > BEFORE YOU START > This chapter continues from the 'Session Keys' page, so be sure to read that one before proceeding with this one. ## Step 1: Prepare for Staking Before you can become an active validator, you need to bond your funds to your node. This involves creating two separate Avail accounts: a `stash` account for holding your funds and a `controller` account for managing staking actions. ### Create Avail Accounts 1. Navigate to the Avail network explorer at [https://explorer.availproject.org/](https://explorer.availproject.org/) and choose the correct network. 2. Create a `stash` account. ### Bond Your Funds > **Note** > > BONDING TIPS > Don't bond all your AVAIL tokens as you'll need some for transaction fees. You can always bond more tokens later. > Note: Withdrawing any bonded amount is subject to the duration of the unbonding period. 1. Navigate to the **Staking** tab in the Explorer. 2. Click on `Stash` to initiate the bonding process. 3. Fill in the bonding preferences. Then click `Bond` and `Sign and Submit`. > **Warning** > > You need at least 50,000 AVAIL to join waiting list. ## Step 2: Manage Session Keys After your node is fully synced, you'll need to rotate and submit your session keys. ### Rotating Session Keys Run the following command on your node machine: > Ensure the node is running with the default HTTP RPC port configured. #### Using Binaries: ```shell curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "author_rotateKeys", "params":[]}' http://localhost:9944 ``` The result is the concatenation of the four public keys. Save the hex-encoded result for the next step and **restart your node**. #### Using Docker: ```shell docker ps ``` You should an output similar to: ``` CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES da097bbeba75 availj/avail:v1.8.0.4 "/entrypoint.sh" 3 seconds ago Up 3 seconds 0.0.0.0:9615->9615/tcp, :::9615->9615/tcp, 0.0.0.0:9944->9944/tcp, 0.0.0.0:30333->30333/tcp, :::9944->9944/tcp musing_cartwright ``` We need the `CONTAINER ID` from the output above: ```shell docker exec -i da097bbeba75 curl -sH "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "author_rotateKeys", "params":[]}' http://localhost:9944 ``` ### Submit Session Keys You must inform the network of your Session keys by signing and submitting the `setKeys` extrinsic. This action associates your validator with your Controller account. 1. Navigate back to the **[Staking](https://explorer.availproject.org/#/staking/actions)** tab. 2. Click on `Set Session Key` and enter the hex-encoded result. 3. Click `Set Session Key` and enter your password when prompted. After submitting the extrinsic, you'll observe that **Set Session Key** changes to **Validate**. Make sure your node is fully synchronized before proceeding further. ## Step 3: Register as a Validator 1. Click `Validate` on the **Staking** tab. 2. Set your validator commission percentage. 3. Enter your password and click `Validate`. ## Step 4: Start Validation Your validator is now prepared to begin the validation process. If you wish to discontinue, you can click the stop icon. Please note that the Avail interface doesn't automatically verify if your node is synchronized; you'll need to confirm this manually. If your node has sufficient stake, the Avail blockchain will likely select it in the next epoch or two. ### Verify Validator Status To verify that your node is ready for possible selection at the end of the next era, follow these steps: 1. Go to the **[Staking](https://explorer.availproject.org/#/staking)** tab and select `Waiting` to see if your account appears. 2. If your node has enough stake, it will be elected in the next era or two. > A new set of validators is chosen every **era**, based on the amount staked. ### Monitor Validator in Action Once your validator node has accrued enough stake, it will be elected for validation. Below is an example image of an elected validator node actively producing blocks. In addition, please check out the guide on validator monitoring available [here](/docs/da/operate/become-a-validator/monitor-your-validator). ## Next Steps Congratulations on successfully setting up your Avail Validator node! You should be seeing something like this: As you move forward, here are some essential actions to consider: 1. **Backup Your Validator**: Ensure you have a secure backup of your validator settings and keys. Refer to the [Backup Guide](/docs/da/operate/become-a-validator/backup-your-validator) for detailed steps. 2. **Start Monitoring**: If you haven't already, set up monitoring tools to keep track of your validator's performance. Check out the [Monitoring Guide](/docs/da/operate/become-a-validator/monitor-your-validator) for recommendations. 3. **Join the Community**: Connect with other validators and the Avail team on the official [Discord Channel](https://discord.com/invite/AvailProject). It's a great place to share experiences, ask questions, and get updates. ### How to Upgrade Your Avail Validator When upgrading Avail nodes there are two options, a faster method and a slower (but safer) method. Both are detailed below, but you only need to use one of them. ## Fast Upgrade While a rapid upgrade is possible, it carries inherent risks if done on a validator node. For instance, if you proceed with the upgrade on a validator node and encounter issues such as database corruption, there's a chance of prolonged downtime. This could lead to your node being removed from the active validator set due to unresponsiveness. This upgrade process is appropriate for non-validator nodes. However, this upgrade process is still possible on validator nodes with careful consideration. The fast upgrade steps are: * Stop the Avail node. ``` sudo systemctl stop avail.service ``` * Locate your Avail binary, create a backup of the current binary, and then uninstall the existing binary by deleting the binary. Proceed to download the most recent binary announced in Discord, which will replace the previous binary version. To provide an example, assuming your existing binary is located at `/home/avail/avail-node/` and is named `data-avail`, and you used the [validator](/docs/da/operate/become-a-validator) setup guidelines while obtaining a pre-built binary from the Avail GitHub repository, proceed as outlined below. ``` cd /home/avail/avail-node/ mv data-avail data-avail-backup wget https://github.com/availproject/avail/releases/download/v1.10.0.0/x86_64-ubuntu-2004-data-avail.tar.gz tar -xvf data-avail-linux-amd64.tar.gz mv data-avail-linux-amd64 data-avail rm data-avail-linux-amd64.tar.gz ``` * Start the Avail node again. ``` sudo systemctl start avail.service ``` * Ensure your node starts syncing with the network, view the logs from the running service. ``` journalctl -f -u avail.service ``` * Also check that your node is visible on telemetry and the version matches the upgrade version. ## Slow & Safe Upgrade This upgrade procedure is most appropriate for validator nodes exclusively and is unnecessary for other types of nodes, such as full, archive, rpc, and so forth. Upgrading a Avail node safely is a careful process to ensure a smooth transition without disruption to the network. Here's a step-by-step guide on how to upgrade a Avail node, including the process of switching nodes using rotated keys: * Preparing for the Upgrade: * Ensure you have a backup of your node's data and keystore files. This ensures you can restore your node in case of any issues during the upgrade process. Familiarize yourself with the release notes and documentation of the new Avail version to understand any specific instructions or requirements. * Setting up Node B: * Install and set up the new version of Avail on a separate server or machine. This will be Node B, which will eventually replace Node A. Configure Node B with the necessary configuration files, including the customizations you had on Node A. Ensure that Node B is fully synchronized with the Avail network before proceeding. * Generating Rotated Keys: * Generate a new set of keys for Node B using `author_rotateKeys`. * Updating Session Keys: * Open Avail Apps and navigate to [Network → Staking](https://testnet.avail.tools/#/staking/actions). You will be able to select from a hidden menu the option to change session keys. * Can enter the hex-encoded value obtained from `author_rotateKeys` and click on **Set Session Key**. * You will now be able to see the new and old hex-encoded value. In the next epoch or two it will only show the new hex-encoded value. * After a few epochs Node B will be performing the validator tasks. You must ensure this by looking in the logs for sealed blocks. You should see `🎁 Prepared block for proposing` appear in the logs of Node B and stop appearing Node A. * You can now upgrade Node A. You can repeat the process to switch back to Node A. > **Warning** > > ENSURE THE NODE HAS SWITCHED > Before turning Node A off you must ensure Node B has become the active validator. In Avail Apps it may show the switch, however there is an epoch delay before the node > fully switches over. The best is to look in the logs and confirm the new node is sealing the blocks. ### How to Run an Avail node ## How to run an Avail node There are four main ways of running an Avail node: 1. By running a pre-built binary. 2. By building from source 3. By running a pre-built image using Docker 4. By assisted deployment with an infrastructure provider > **Note** > > **LOOKING TO BE AN RPC PROVIDER?** > > We welcome all community members who are looking to run an RPC node on Avail. > While the exact config of your node will depend on your unique requirements, the following flags are > required to make sure your node can be used to access all RPC methods: > > ```bash showLineNumbers filename="avail-node flags" > --state-pruning archive > --blocks-pruning archive > --rpc-methods Safe > --rpc-cors all > --unsafe-rpc-external > --enable-kate-rpc > ``` > >
> > Description of the flags: > > > * **--state-pruning archive**: > > Specify the state pruning mode. > This mode specifies when the block's state (ie, storage) should be pruned (ie, removed) from the database. This setting can only > be set on the first creation of the database. Every subsequent run will load the pruning mode from the database and will error > if the stored mode doesn't match this CLI value. It is fine to drop this CLI flag for subsequent runs. Possible values: - > archive: Keep the state of all blocks. - `archive-canonical`: Keep only the state of finalized blocks. - number Keep the state of > the last number of finalized blocks. \[default: 256] > > * **--blocks-pruning archive**: > > Specify the blocks pruning mode. > This mode specifies when the block's body (including justifications) should be pruned (ie, removed) from the database. Possible > values: - `archive`: Keep all blocks. - `archive-canonical`: Keep only finalized blocks. - number Keep the last `number` of > finalized blocks. > > * **--rpc-methods Safe**: > > RPC methods to expose. > \[default: auto] \ > Possible values: > > * auto: Expose every RPC method only when RPC is listening on `localhost`, otherwise serve only safe RPC methods > * safe: Allow only a safe subset of RPC methods > * unsafe: Expose every RPC method (even potentially unsafe ones) > > * **--rpc-cors all**: > > Specify browser *origins* allowed to access the HTTP & WS RPC servers. > A comma-separated list of origins (protocol://domain or special `null` value). Value of `all` will disable origin validation. > > * **--unsafe-rpc-external**: > > Listen to all RPC interfaces. > > * **--enable-kate-rpc**: > > Enable the Kate pallet. >
> > * Looking for a list of all available config flags? Check out the [last section of this page](/docs/da/operate/run-a-full-node/full-node#additional-configs). #### Run a pre-built binary 1. Go to the [Avail node GitHub releases page](https://github.com/availproject/avail/releases/). There you will see a lot of pre-built binaries for each version of the Avail node. 2. Please download the binary suitable from your system, of the `latest` version. You can do this using the GUI or by running the following command in your terminal: ```bash curl -L -O https://github.com/availproject/avail/releases/download//.tar.gz ``` 3. Extract the downloaded file by opening a terminal in the location of the downloaded file and using the following command: ```bash tar -xzvf .tar.gz ``` > Your terminal should now look something like this:

Extracted Avail node binary

* The file in red is what we downloaded to our system. * The file in green is the extracted binary. 4. Once extracted, you will see a pre-built, executable binary named `avail-node` in the same directory. You can run this binary using the following command: ```bash ./avail-node --name a-random-name --chain mainnet -d ./output ``` 5. Your terminal output should look something like this: ```bash 2024-04-29 07:48:22 Avail Node 2024-04-29 07:48:22 ✌️ version 2.1.1-8608dc47f00 2024-04-29 07:48:22 ❤️ by Avail Project , 2017-2024 2024-04-29 07:48:22 📋 Chain specification: Avail Turing Network 2024-04-29 07:48:22 🏷 Node name: possible-point-3102 2024-04-29 07:48:22 👤 Role: FULL 2024-04-29 07:48:22 💾 Database: ParityDb at ./output/chains/avail_turing_network/paritydb/full 2024-04-29 07:48:27 🔨 Initializing Genesis block/state (state: 0x5603…9c01, header-hash: 0xd3d2…8b70) 2024-04-29 07:48:27 👴 Loading GRANDPA authority set from genesis on what appears to be first startup. 2024-04-29 07:48:29 👶 Creating empty BABE epoch changes on what appears to be first startup. 2024-04-29 07:48:29 🏷 Local node identity is: 12D3KooWELgzaRZqsHNyUodhZZF7A1ydsRpgLsY7fojDegKni4YF 2024-04-29 07:48:29 Prometheus metrics extended with avail metrics 2024-04-29 07:48:29 💻 Operating system: linux 2024-04-29 07:48:29 💻 CPU architecture: x86_64 2024-04-29 07:48:29 💻 Target environment: gnu 2024-04-29 07:48:29 💻 CPU: DO-Premium-Intel 2024-04-29 07:48:29 💻 CPU cores: 4 2024-04-29 07:48:29 💻 Memory: 7937MB 2024-04-29 07:48:29 💻 Kernel: 5.15.0-105-generic 2024-04-29 07:48:29 💻 Linux distribution: Ubuntu 22.04.4 LTS 2024-04-29 07:48:29 💻 Virtual machine: yes 2024-04-29 07:48:29 📦 Highest known block at #0 2024-04-29 07:48:29 Running JSON-RPC server: addr=127.0.0.1:9944, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"] 2024-04-29 07:48:29 🏁 CPU score: 950.72 MiBs 2024-04-29 07:48:29 🏁 Memory score: 4.02 GiBs 2024-04-29 07:48:29 🏁 Disk score (seq. writes): 845.72 MiBs 2024-04-29 07:48:29 🏁 Disk score (rand. writes): 338.52 MiBs 2024-04-29 07:48:29 〽️ Prometheus exporter started at 127.0.0.1:9615 2024-04-29 07:48:30 🔍 Discovered new external address for our node: /ip4/139.59.94.121/tcp/30333/ws/p2p/12D3KooWELgzaRZqsHNyUodhZZF7A1ydsRpgLsY7fojDegKni4YF 2024-04-29 07:48:34 ⚙️ Syncing, target=#137399 (9 peers), best: #1000 (0x9e8f…55ab), finalized #512 (0x0a9a…875a), ⬇ 316.3kiB/s ⬆ 14.2kiB/s 2024-04-29 07:48:39 ⚙️ Syncing 235.4 bps, target=#137399 (9 peers), best: #2177 (0x5828…e9da), finalized #2048 (0x2f65…3b2e), ⬇ 113.3kiB/s ⬆ 5.5kiB/s 2024-04-29 07:48:43 [3097] 💸 generated 8 npos targets 2024-04-29 07:48:43 [3097] 💸 generated 8 npos voters, 8 from validators and 0 nominators 2024-04-29 07:48:43 [#3097] 🗳 creating a snapshot with metadata SolutionOrSnapshotSize { voters: 8, targets: 8 } 2024-04-29 07:48:43 [#3097] 🗳 Starting phase Signed, round 1. 2024-04-29 07:48:44 [#3277] 🗳 Starting phase Unsigned((true, 3277)), round 1. 2024-04-29 07:48:44 [#3278] 🗳 queued unsigned solution with score ElectionScore { minimal_stake: 184467440819699, sum_stake: 184467440819699, sum_stake_squared: 34028236722569152873026450601 } 2024-04-29 07:48:44 ⚙️ Syncing 236.0 bps, target=#137400 (10 peers), best: #3357 (0x0c50…7d21), finalized #3072 (0x2803…c15b), ⬇ 244.0kiB/s ⬆ 20.2kiB/s 2024-04-29 07:48:44 [#3457] 🗳 Starting phase Off, round 2. 2024-04-29 07:48:44 [3457] 💸 new validator set of size 1 has been processed for era 1 2024-04-29 07:48:49 ⚙️ Syncing 206.2 bps, target=#137400 (10 peers), best: #4388 (0x2d3d…6b93), finalized #4177 (0x58f8…9518), ⬇ 261.5kiB/s ⬆ 11.6kiB/s 2024-04-29 07:48:54 ⚙️ Syncing 232.0 bps, target=#137400 (10 peers), best: #5548 (0x1aef…1c46), finalized #5120 (0x274f…e5d7), ⬇ 122.7kiB/s ⬆ 6.9kiB/s 2024-04-29 07:48:59 ⚙️ Syncing 118.2 bps, target=#137400 (10 peers), best: #6139 (0x9e52…af00), finalized #5632 (0x5297…a001), ⬇ 66.5kiB/s ⬆ 4.9kiB/s 2024-04-29 07:49:04 ⚙️ Syncing 185.7 bps, target=#137401 (10 peers), best: #7068 (0x911d…666a), finalized #6656 (0xdd79…2e5e), ⬇ 80.7kiB/s ⬆ 1.5kiB/s 2024-04-29 07:49:05 [7417] 💸 generated 9 npos targets 2024-04-29 07:49:05 [7417] 💸 generated 9 npos voters, 9 from validators and 0 nominators 2024-04-29 07:49:05 [#7417] 🗳 creating a snapshot with metadata SolutionOrSnapshotSize { voters: 9, targets: 9 } 2024-04-29 07:49:05 [#7417] 🗳 Starting phase Signed, round 2. 2024-04-29 07:49:06 [#7597] 🗳 Starting phase Unsigned((true, 7597)), round 2. 2024-04-29 07:49:06 [#7598] 🗳 queued unsigned solution with score ElectionScore { minimal_stake: 184447246591607, sum_stake: 1475577972732856, sum_stake_squared: 272166294201800640629142739592 } 2024-04-29 07:49:07 [#7777] 🗳 Finalized election round with compute Unsigned. 2024-04-29 07:49:07 [#7777] 🗳 Starting phase Off, round 3. 2024-04-29 07:49:07 [7777] 💸 new validator set of size 8 has been processed for era 2 2024-04-29 07:49:09 ⚙️ Syncing 206.2 bps, target=#137401 (10 peers), best: #8099 (0x559a…9c2e), finalized #7680 (0x84b6…abc0), ⬇ 103.9kiB/s ⬆ 0.9kiB/s 2024-04-29 07:49:14 ⚙️ Syncing 204.4 bps, target=#137401 (10 peers), best: #9121 (0xf95e…5a17), finalized #8704 (0x6e49…33cd), ⬇ 98.0kiB/s ⬆ 1.5kiB/s ``` #### Build from source > **Note** > > Please note that the following instructions were tested specifically on an Ubuntu machine. If you are using a different operating system, you may need to adjust the commands accordingly. > However, they should work on all Debian installations, and with minor tweaks, on all Linux distros. Before proceeding, install the required dependencies: 1. The Rust toolchain: Go to [rust-lang.org/tools/install](https://www.rust-lang.org/tools/install) and follow the instructions to install the Rust toolchain onto your system. Verify Rust is installed on your system by running: ```bash rustc --version ``` > **Note** > > If the installation process seemed to go smoothly and the command above still doesn't work: > > 1. Close your current terminal and try it in a new one. > 2. Alternatively, in your old terminal, run `source $HOME/.cargo/env` and then run `source $HOME/.cargo/env` again. If you still encounter issues with Rust's installation, refer to the [Rust installation guide](https://www.rust-lang.org/tools/install) for troubleshooting tips. 2. Make sure your Linux distro is up-to-date by running: ```bash apt update && apt upgrade ``` 3. Make sure some common dependencies are installed using: ```bash apt install make clang pkg-config libssl-dev build-essential git curl llvm libudev-dev cmake protobuf-compiler -y ``` > **Note** > > Some of these commands might not work without being prefixed by 'sudo'. > However, the 'sudo' command gives the terminal root access, so be careful > when using it. 4. Clone the Avail node repo and move your terminal into it: ```bash git clone https://github.com/availproject/avail.git && cd avail ``` 5. Build the Avail node by executing this command: ```bash cargo build --release ``` > **Note** > > The build process may take some time, depending on your system's specifications. > On a system with a Quad-core processor & 8GBs of RAM, the build process typically takes > around 35-40 minutes. 6. Once your Avail node is compiled locally, you can run it using: ```bash cargo run --release -- --name a-random-name --chain mainnet -d ./output ``` 7. Your terminal output should look something like this: ```bash 2024-04-29 07:48:22 Avail Node 2024-04-29 07:48:22 ✌️ version 2.1.1-8608dc47f00 2024-04-29 07:48:22 ❤️ by Avail Project , 2017-2024 2024-04-29 07:48:22 📋 Chain specification: Avail Turing Network 2024-04-29 07:48:22 🏷 Node name: possible-point-3102 2024-04-29 07:48:22 👤 Role: FULL 2024-04-29 07:48:22 💾 Database: ParityDb at ./output/chains/avail_turing_network/paritydb/full 2024-04-29 07:48:27 🔨 Initializing Genesis block/state (state: 0x5603…9c01, header-hash: 0xd3d2…8b70) 2024-04-29 07:48:27 👴 Loading GRANDPA authority set from genesis on what appears to be first startup. 2024-04-29 07:48:29 👶 Creating empty BABE epoch changes on what appears to be first startup. 2024-04-29 07:48:29 🏷 Local node identity is: 12D3KooWELgzaRZqsHNyUodhZZF7A1ydsRpgLsY7fojDegKni4YF 2024-04-29 07:48:29 Prometheus metrics extended with avail metrics 2024-04-29 07:48:29 💻 Operating system: linux 2024-04-29 07:48:29 💻 CPU architecture: x86_64 2024-04-29 07:48:29 💻 Target environment: gnu 2024-04-29 07:48:29 💻 CPU: DO-Premium-Intel 2024-04-29 07:48:29 💻 CPU cores: 4 2024-04-29 07:48:29 💻 Memory: 7937MB 2024-04-29 07:48:29 💻 Kernel: 5.15.0-105-generic 2024-04-29 07:48:29 💻 Linux distribution: Ubuntu 22.04.4 LTS 2024-04-29 07:48:29 💻 Virtual machine: yes 2024-04-29 07:48:29 📦 Highest known block at #0 2024-04-29 07:48:29 Running JSON-RPC server: addr=127.0.0.1:9944, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"] 2024-04-29 07:48:29 🏁 CPU score: 950.72 MiBs 2024-04-29 07:48:29 🏁 Memory score: 4.02 GiBs 2024-04-29 07:48:29 🏁 Disk score (seq. writes): 845.72 MiBs 2024-04-29 07:48:29 🏁 Disk score (rand. writes): 338.52 MiBs 2024-04-29 07:48:29 〽️ Prometheus exporter started at 127.0.0.1:9615 2024-04-29 07:48:30 🔍 Discovered new external address for our node: /ip4/139.59.94.121/tcp/30333/ws/p2p/12D3KooWELgzaRZqsHNyUodhZZF7A1ydsRpgLsY7fojDegKni4YF 2024-04-29 07:48:34 ⚙️ Syncing, target=#137399 (9 peers), best: #1000 (0x9e8f…55ab), finalized #512 (0x0a9a…875a), ⬇ 316.3kiB/s ⬆ 14.2kiB/s 2024-04-29 07:48:39 ⚙️ Syncing 235.4 bps, target=#137399 (9 peers), best: #2177 (0x5828…e9da), finalized #2048 (0x2f65…3b2e), ⬇ 113.3kiB/s ⬆ 5.5kiB/s 2024-04-29 07:48:43 [3097] 💸 generated 8 npos targets 2024-04-29 07:48:43 [3097] 💸 generated 8 npos voters, 8 from validators and 0 nominators 2024-04-29 07:48:43 [#3097] 🗳 creating a snapshot with metadata SolutionOrSnapshotSize { voters: 8, targets: 8 } 2024-04-29 07:48:43 [#3097] 🗳 Starting phase Signed, round 1. 2024-04-29 07:48:44 [#3277] 🗳 Starting phase Unsigned((true, 3277)), round 1. 2024-04-29 07:48:44 [#3278] 🗳 queued unsigned solution with score ElectionScore { minimal_stake: 184467440819699, sum_stake: 184467440819699, sum_stake_squared: 34028236722569152873026450601 } 2024-04-29 07:48:44 ⚙️ Syncing 236.0 bps, target=#137400 (10 peers), best: #3357 (0x0c50…7d21), finalized #3072 (0x2803…c15b), ⬇ 244.0kiB/s ⬆ 20.2kiB/s 2024-04-29 07:48:44 [#3457] 🗳 Starting phase Off, round 2. 2024-04-29 07:48:44 [3457] 💸 new validator set of size 1 has been processed for era 1 2024-04-29 07:48:49 ⚙️ Syncing 206.2 bps, target=#137400 (10 peers), best: #4388 (0x2d3d…6b93), finalized #4177 (0x58f8…9518), ⬇ 261.5kiB/s ⬆ 11.6kiB/s 2024-04-29 07:48:54 ⚙️ Syncing 232.0 bps, target=#137400 (10 peers), best: #5548 (0x1aef…1c46), finalized #5120 (0x274f…e5d7), ⬇ 122.7kiB/s ⬆ 6.9kiB/s 2024-04-29 07:48:59 ⚙️ Syncing 118.2 bps, target=#137400 (10 peers), best: #6139 (0x9e52…af00), finalized #5632 (0x5297…a001), ⬇ 66.5kiB/s ⬆ 4.9kiB/s 2024-04-29 07:49:04 ⚙️ Syncing 185.7 bps, target=#137401 (10 peers), best: #7068 (0x911d…666a), finalized #6656 (0xdd79…2e5e), ⬇ 80.7kiB/s ⬆ 1.5kiB/s 2024-04-29 07:49:05 [7417] 💸 generated 9 npos targets 2024-04-29 07:49:05 [7417] 💸 generated 9 npos voters, 9 from validators and 0 nominators 2024-04-29 07:49:05 [#7417] 🗳 creating a snapshot with metadata SolutionOrSnapshotSize { voters: 9, targets: 9 } 2024-04-29 07:49:05 [#7417] 🗳 Starting phase Signed, round 2. 2024-04-29 07:49:06 [#7597] 🗳 Starting phase Unsigned((true, 7597)), round 2. 2024-04-29 07:49:06 [#7598] 🗳 queued unsigned solution with score ElectionScore { minimal_stake: 184447246591607, sum_stake: 1475577972732856, sum_stake_squared: 272166294201800640629142739592 } 2024-04-29 07:49:07 [#7777] 🗳 Finalized election round with compute Unsigned. 2024-04-29 07:49:07 [#7777] 🗳 Starting phase Off, round 3. 2024-04-29 07:49:07 [7777] 💸 new validator set of size 8 has been processed for era 2 2024-04-29 07:49:09 ⚙️ Syncing 206.2 bps, target=#137401 (10 peers), best: #8099 (0x559a…9c2e), finalized #7680 (0x84b6…abc0), ⬇ 103.9kiB/s ⬆ 0.9kiB/s 2024-04-29 07:49:14 ⚙️ Syncing 204.4 bps, target=#137401 (10 peers), best: #9121 (0xf95e…5a17), finalized #8704 (0x6e49…33cd), ⬇ 98.0kiB/s ⬆ 1.5kiB/s ``` #### Using Docker > **Note** > > 1. This part of the guide assumes you have [Docker engine installed](https://docs.docker.com/engine/) > on your system. > > 2. You can quickly check if it is installed by running: > > ```bash > docker run hello-world > ``` > > 3. It is recommended to run Docker without using the 'sudo' command. > Check out [these post-installation instructions in Docker's docs](https://docs.docker.com/engine/install/linux-postinstall/) to do so. To download and run an Avail node using Docker: 1. Simply run the following command in your terminal: ```bash docker run --restart=on-failure -d -v /root/avail/node-data:/da/node-data -p 9944:9944 -p 30333:30333 docker.io/availj/avail: --chain mainnet -d ./output --name a-random-name ``` * -d runs the container in the background * -v mounts a volume into the container * -p publishes containers port to the host machine 2. To configure Docker specific flags you can refer to Docker's documentation, and you can check out the Additional configs section in this page to get more information on how to configure the Avail node. 3. To a persistent output from the container, you can run: ```bash docker logs -f ``` 4. After some time, your terminal output should look something like this: ```bash 2024-04-30 16:37:49 💤 Idle (11 peers), best: #143238 (0xde00…04e0), finalized #143236 (0x5624…13b1), ⬇ 1.0kiB/s ⬆ 2.3kiB/s 2024-04-30 16:37:54 💤 Idle (11 peers), best: #143238 (0xde00…04e0), finalized #143236 (0x5624…13b1), ⬇ 1.9kiB/s ⬆ 4.5kiB/s 2024-04-30 16:37:59 💤 Idle (11 peers), best: #143238 (0xde00…04e0), finalized #143236 (0x5624…13b1), ⬇ 2.9kiB/s ⬆ 4.2kiB/s 2024-04-30 16:38:00 ✨ Imported #143239 (0x43fb…a69f) 2024-04-30 16:38:04 💤 Idle (11 peers), best: #143239 (0x43fb…a69f), finalized #143237 (0xbb06…d3ec), ⬇ 5.1kiB/s ⬆ 3.7kiB/s 2024-04-30 16:38:09 💤 Idle (11 peers), best: #143239 (0x43fb…a69f), finalized #143237 (0xbb06…d3ec), ⬇ 2.3kiB/s ⬆ 4.8kiB/s 2024-04-30 16:38:14 💤 Idle (11 peers), best: #143239 (0x43fb…a69f), finalized #143237 (0xbb06…d3ec), ⬇ 1.7kiB/s ⬆ 4.4kiB/s 2024-04-30 16:38:19 💤 Idle (11 peers), best: #143239 (0x43fb…a69f), finalized #143237 (0xbb06…d3ec), ⬇ 3.9kiB/s ⬆ 7.0kiB/s 2024-04-30 16:38:20 ✨ Imported #143240 (0xc8dd…6b41) 2024-04-30 16:38:24 💤 Idle (11 peers), best: #143240 (0xc8dd…6b41), finalized #143237 (0xbb06…d3ec), ⬇ 4.7kiB/s ⬆ 8.1kiB/s 2024-04-30 16:38:29 💤 Idle (12 peers), best: #143240 (0xc8dd…6b41), finalized #143238 (0xde00…04e0), ⬇ 3.8kiB/s ⬆ 4.7kiB/s 2024-04-30 16:38:34 💤 Idle (12 peers), best: #143240 (0xc8dd…6b41), finalized #143238 (0xde00…04e0), ⬇ 2.2kiB/s ⬆ 5.0kiB/s 2024-04-30 16:38:39 💤 Idle (12 peers), best: #143240 (0xc8dd…6b41), finalized #143238 (0xde00…04e0), ⬇ 1.6kiB/s ⬆ 4.2kiB/s 2024-04-30 16:38:40 ✨ Imported #143241 (0x4d2c…e08a) 2024-04-30 16:38:40 ♻️ Reorg on #143241,0x4d2c…e08a to #143241,0x2b03…6360, common ancestor #143240,0xc8dd…6b41 2024-04-30 16:38:40 ✨ Imported #143241 (0x2b03…6360) 2024-04-30 16:38:44 💤 Idle (12 peers), best: #143241 (0x2b03…6360), finalized #143238 (0xde00…04e0), ⬇ 5.2kiB/s ⬆ 6.7kiB/s 2024-04-30 16:38:49 💤 Idle (12 peers), best: #143241 (0x2b03…6360), finalized #143239 (0x43fb…a69f), ⬇ 5.3kiB/s ⬆ 6.8kiB/s 2024-04-30 16:38:54 💤 Idle (12 peers), best: #143241 (0x2b03…6360), finalized #143239 (0x43fb…a69f), ⬇ 2.1kiB/s ⬆ 2.9kiB/s 2024-04-30 16:38:59 💤 Idle (12 peers), best: #143241 (0x2b03…6360), finalized #143239 (0x43fb…a69f), ⬇ 3.1kiB/s ⬆ 7.2kiB/s 2024-04-30 16:39:00 ✨ Imported #143242 (0x807a…e405) 2024-04-30 16:39:00 ♻️ Reorg on #143242,0x807a…e405 to #143242,0xbf6b…7cfb, common ancestor #143241,0x2b03…6360 2024-04-30 16:39:00 ✨ Imported #143242 (0xbf6b…7cfb) 2024-04-30 16:39:04 💤 Idle (12 peers), best: #143242 (0xbf6b…7cfb), finalized #143239 (0x43fb…a69f), ⬇ 6.1kiB/s ⬆ 6.8kiB/s 2024-04-30 16:39:09 💤 Idle (12 peers), best: #143242 (0xbf6b…7cfb), finalized #143240 (0xc8dd…6b41), ⬇ 23.1kiB/s ⬆ 31.6kiB/s 2024-04-30 16:39:14 💤 Idle (12 peers), best: #143242 (0xbf6b…7cfb), finalized #143240 (0xc8dd…6b41), ⬇ 12.6kiB/s ⬆ 62.3kiB/s 2024-04-30 16:39:19 💤 Idle (12 peers), best: #143242 (0xbf6b…7cfb), finalized #143240 (0xc8dd…6b41), ⬇ 15.7kiB/s ⬆ 52.6kiB/s 2024-04-30 16:39:20 ✨ Imported #143243 (0x1de9…4a0b) 2024-04-30 16:39:24 💤 Idle (12 peers), best: #143243 (0x1de9…4a0b), finalized #143240 (0xc8dd…6b41), ⬇ 16.7kiB/s ⬆ 43.6kiB/s 2024-04-30 16:39:29 💤 Idle (12 peers), best: #143243 (0x1de9…4a0b), finalized #143241 (0x2b03…6360), ⬇ 7.1kiB/s ⬆ 34.3kiB/s 2024-04-30 16:39:34 💤 Idle (12 peers), best: #143243 (0x1de9…4a0b), finalized #143241 (0x2b03…6360), ⬇ 1.9kiB/s ⬆ 3.3kiB/s 2024-04-30 16:39:39 💤 Idle (12 peers), best: #143243 (0x1de9…4a0b), finalized #143241 (0x2b03…6360), ⬇ 27.4kiB/s ⬆ 31.7kiB/s 2024-04-30 16:39:40 ✨ Imported #143244 (0xb05b…2158) 2024-04-30 16:39:44 💤 Idle (12 peers), best: #143244 (0xb05b…2158), finalized #143241 (0x2b03…6360), ⬇ 13.8kiB/s ⬆ 35.3kiB/s 2024-04-30 16:39:49 💤 Idle (12 peers), best: #143244 (0xb05b…2158), finalized #143242 (0xbf6b…7cfb), ⬇ 8.2kiB/s ⬆ 131.8kiB/s 2024-04-30 16:39:54 💤 Idle (12 peers), best: #143244 (0xb05b…2158), finalized #143242 (0xbf6b…7cfb), ⬇ 7.0kiB/s ⬆ 4.1kiB/s 2024-04-30 16:39:59 💤 Idle (12 peers), best: #143244 (0xb05b…2158), finalized #143242 (0xbf6b…7cfb), ⬇ 16.3kiB/s ⬆ 44.4kiB/s 2024-04-30 16:40:00 ✨ Imported #143245 (0xe42d…9b4f) 2024-04-30 16:40:00 ♻️ Reorg on #143245,0xe42d…9b4f to #143245,0x0b16…c2ac, common ancestor #143244,0xb05b…2158 2024-04-30 16:40:00 ✨ Imported #143245 (0x0b16…c2ac) 2024-04-30 16:40:04 💤 Idle (12 peers), best: #143245 (0x0b16…c2ac), finalized #143242 (0xbf6b…7cfb), ⬇ 20.5kiB/s ⬆ 40.6kiB/s 2024-04-30 16:40:09 💤 Idle (12 peers), best: #143245 (0x0b16…c2ac), finalized #143243 (0x1de9…4a0b), ⬇ 4.6kiB/s ⬆ 11.4kiB/s 2024-04-30 16:40:14 💤 Idle (12 peers), best: #143245 (0x0b16…c2ac), finalized #143243 (0x1de9…4a0b), ⬇ 52.3kiB/s ⬆ 88.3kiB/s 2024-04-30 16:40:19 💤 Idle (12 peers), best: #143245 (0x0b16…c2ac), finalized #143243 (0x1de9…4a0b), ⬇ 33.4kiB/s ⬆ 40.9kiB/s 2024-04-30 16:40:20 ✨ Imported #143246 (0x8289…0798) ``` #### Assisted Deployment [OnFinality](https://onfinality.io) is a blockchain native infrastructure provider supporting the Avail ecosystem with private Archive, Full, and Validator nodes. Your Avail node will be fully synced and ready to use within minutes. > **Note** > > To run a node with OnFinality, first [Sign Up](https://app.onfinality.io/signup) for an OnFinality account. > > In this guide we will show you how to run a self-service Avail node. For a fully managed setup please contact [support@onfinality.io](mailto:support@onfinality.io) 1. Open the [OnFinality Portal](https://app.onfinality.io) and navigate to the "Dedicated Nodes" menu 2. Select "Avail" > "Deploy Node"

Deploy Avail Node with OnFinality - Select Avail

3. Enter your node's configuration, including: * **Name:** The name you wish to give your node. If you connect to Telemetry this name will be public * **Node Type:** Full, Archive, or Validator. Note: Lightning Restore is supported for Archive and Validator so your node will sync faster. * **Image Version:** The (Recommended) version is... recommended! * **Region:** Select the region which is closest to your applications which will use the node. Look out for the Lightning Restore icon for faster syncing. * **Configuration:** The Compute size and storage of your node. If in doubt, start with the recommended configuration and scale as necessary.

Deploy Avail Node with OnFinality - Select Configuration

Press "Next". 4. Review your node's Launch Arguments. See the complete commands and arguments supported by Avail at the bottom of this page.

Deploy Avail Node with OnFinality - Review Launch Arguments

Press "Next". 5. Review your node's configuration and press "Deploy Node"

Deploy Avail Node with OnFinality - Review Deployment

6. Your node will initialize and be ready within several minutes. Confirm that the Syncing Status is "Synced" and the CPU is within a healthy range.

Deploy Avail Node with OnFinality - Get API Endpoints

Congratulations, your Avail node is now ready to use! Copy the API Endpoints and fire away > **Note** > > The team at OnFinality will update your node for you as new Avail image versions are released. > > For more information, visit OnFinality's guide to [Maintaining and Upgrading your Dedicated Node](https://documentation.onfinality.io/support/maintain-and-upgrade-your-dedicated-node) Your node will also appear on the [Avail Telemetry site](https://telemetry.avail.so/), listed under the "Node name" from the node command output. Be sure to select the appropriate network tab at the top to view your node's status. ## Additional configs The Avail node is a highly customizable piece of software. You can fetch a list of supported commands and flags using: ```bash ./avail-node --help ``` Alternatively, you can check out [this notion page](https://avail-project.notion.site/Commands-and-options-supported-by-the-Avail-node-838b7b1fb7cd496a869987e7b7a72fdc?pvs=74). > **Note** > > Please note that the notion page may not always be updated. > The best way to reliably get the latest config options will be `./avail-node --help`. ### System Requirements ## System Requirements This is the hardware configuration required to set up an Avail node: | Component | Minimum | Recommended | | ---------------------------- | :------: | :---------: | | RAM | 8GB | 16GB | | CPU (amd64/x86 architecture) | 4 core | 8 core | | Storage (SSD) | 20-40 GB | 200-300 GB | > While we do not favor any operating system, more secure and stable Linux server distributions (like CentOS) should be preferred over desktop operating systems (like Mac OS and Windows). Also, the minimum storage requirements will change over time as the network grows. > It is recommended to use more than the minimum requirements to run a robust full node. ## Methods to Run an Avail Node There are four primary methods to run an Avail node, each with its own set of instructions: 1. **Using Binaries:** You can follow the instructions provided in the next page for setting up an Avail node using binary releases. This method is suitable for users who prefer manual installation and configuration. For reference, you can also explore the [GitHub Releases](https://github.com/availproject/avail/releases) page for a list of binary releases. 2. **Building from source:** The Avail node is based on open-sourced code. Feel free to [clone the repo](https://github.com/availproject/avail) and build it locally. 3. **Using Docker:** If you have docker engine installed on your machine, you can use it to run a [pre-built docker image for the Avail node](https://hub.docker.com/r/availj/avail/tags). 4. **Assisted Deployment:** If you prefer running your Avail node with the help of an infrastructure provider, you can run an avail node on [OnFinality](https://onfinality.io/networks/avail) and have a fully synced node ready to use in minutes ### How to Run an Avail light client > **Note** > > **LOOKING FOR THE LIGHT CLIENT API REFERENCE?** > Go to [light client API reference](/docs/da/api-reference/avail-lc-api) 1. Use [Availup](https://github.com/availproject/availup) to run the light client. 2. Download and run a pre-built binary. 3. Build your Light client from source ## Latest release You can find the latest release binary in the [`avail-light`](https://github.com/availproject/avail-light) repository. > **Note** > > **RECOMMENDED VERSION** > You can find the latest release of the Avail LC from [our Github repo](https://github.com/availproject/avail-light). > We recommend devs to use the `Latest` release. ## Light client modes The Avail light client has two main modes of operation: 1. **Light-client mode**: The basic mode of operation and is always active no matter the mode selected. If an `app_id` is not provided (or is = 0), this mode will commence. On each header received the client does random sampling using two mechanisms 2. **App-client mode**: If an `app_id > 0` is given, the application client (part of the light client) downloads all data specific to that App ID, reconstructs it and persists it locally. This data can then be accessed via a local HTTP endpoint. > **Note** > > **WE RECOMMEND LEARNING ABOUT APP IDs on AVAIL DA** > App IDs are an important concept in the context of Avail. We recommend you go through [this page in our docs](/docs/da/concepts/app-ids) to understand how they work before moving forward. ## Running the light client #### Light-client mode > **Note** > > **CONFIG FLAGS** > Availup supports many different config flags to support your needs. > Detailed documentation for them can be found [in our Github repo](https://github.com/availproject/availup?tab=readme-ov-file#availup). **[`availup`](https://github.com/availproject/availup)** is the recommended way of running the Avail light client for most users. `availup` is a shell wrapper that allows you to spin up your own instance of the Avail light client with a simple `curl` command. > **Note** > > To run the Avail LC using `availup`, make sure you have [`curl`](https://curl.se/) installed on your system. To check, quickly: > > ```sh > curl --version > ``` 1. To spin up an Avail light client on the Turing testnet, just run this one command in your terminal: ```sh curl -sL1 avail.sh | bash ``` 2. If everything goes well, the client output will look like this:
Sample output ```shell 2024-03-20T10:50:25.528628Z INFO avail_light::light_client: Processing finalized block block_number=562690 block_delay=20 2024-03-20T10:50:25.528706Z INFO avail_light::light_client: Random cells generated: 10 block_number=562690 cells_requested=10 2024-03-20T10:50:26.069497Z INFO avail_light::network: Cells fetched from DHT block_number=562690 cells_total=10 cells_fetched=0 cells_verified=0 fetch_elapsed=540.755792ms proof_verification_elapsed=2.208µs 2024-03-20T10:50:28.322706Z INFO avail_light::network: Cells fetched from RPC block_number=562690 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=2.232714917s proof_verification_elapsed=20.404208ms 2024-03-20T10:50:28.322987Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562690 confidence=99.90234375 2024-03-20T10:50:28.323134Z INFO avail_light::light_client: Sleeping for 14.61143875s seconds 2024-03-20T10:50:28.323154Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:50:28.859369Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562690: 0/10. Duration: 0 2024-03-20T10:50:41.535425Z INFO avail_light::network::rpc::subscriptions: New justification at block no.: 562692, hash: 0x3b602253298ce9bec9b5b8f0c8767f14502ccaa17a003dfba77f9d90edeaf5da 2024-03-20T10:50:41.709011Z INFO avail_light::network::rpc::subscriptions: Header no.: 562692 2024-03-20T10:50:41.709557Z INFO avail_light::network::rpc::subscriptions: Number of matching signatures: 5/7 for block 562692, set_id 223 2024-03-20T10:50:41.709574Z INFO avail_light::network::rpc::subscriptions: Storing finality checkpoint at block 562692 2024-03-20T10:50:41.709908Z INFO avail_light::network::rpc::subscriptions: Sending finalized block 562692 2024-03-20T10:50:41.709966Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:50:42.936699Z INFO avail_light::light_client: Processing finalized block block_number=562691 block_delay=20 2024-03-20T10:50:42.936761Z INFO avail_light::light_client: Random cells generated: 10 block_number=562691 cells_requested=10 2024-03-20T10:50:43.472932Z INFO avail_light::network: Cells fetched from DHT block_number=562691 cells_total=10 cells_fetched=0 cells_verified=0 fetch_elapsed=536.136083ms proof_verification_elapsed=3.042µs 2024-03-20T10:50:46.513570Z INFO avail_light::network: Cells fetched from RPC block_number=562691 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=3.022786041s proof_verification_elapsed=17.810542ms 2024-03-20T10:50:46.513706Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562691 confidence=99.90234375 2024-03-20T10:50:46.513785Z INFO avail_light::light_client: Sleeping for 15.195224667s seconds 2024-03-20T10:50:46.513795Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:50:47.056255Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562691: 0/10. Duration: 0 ```
#### App-client mode > **Note** > > **CONFIG FLAGS** > You can run the Avail light client with different flags to configure it according to your needs. > Detailed documentation for them can be found [in our Github repo](https://github.com/availproject/avail-light/blob/main/client/README.md#options). You can also download and run a pre-built binary of the Avail light client. To do so: 1. Download the [recommended version of the binary](https://github.com/availproject/avail-light/releases) that is compatible with your operating system. 2. Move the `.tar` file into a convenient directory and extract it to reveal the `avail-light` binary. 3. Open a terminal in that location and run: For linux machines that run on `x86_64` based Intel or `amd64` based AMD processors, run: ```sh ./avail-light-linux-amd64 --network mainnet ``` #### apple-x86_64 For MacOS machines that run on `x86_64` based Intel processors, run: ```sh ./avail-light-apple-x86_64 --network mainnet ``` #### apple-arm64 For MacOS machines that run on newer `arm64` based M-series processors, run: ```sh ./avail-light-apple-arm64 --network mainnet ``` > **Note** > > You can configure the run command with a variety of [config flags](https://github.com/availproject/avail-light/blob/main/client/README.md#options). 4. If everything goes well, the client output will look like this:
Sample output ```shell 2024-03-20T10:50:25.528628Z INFO avail_light::light_client: Processing finalized block block_number=562690 block_delay=20 2024-03-20T10:50:25.528706Z INFO avail_light::light_client: Random cells generated: 10 block_number=562690 cells_requested=10 2024-03-20T10:50:26.069497Z INFO avail_light::network: Cells fetched from DHT block_number=562690 cells_total=10 cells_fetched=0 cells_verified=0 fetch_elapsed=540.755792ms proof_verification_elapsed=2.208µs 2024-03-20T10:50:28.322706Z INFO avail_light::network: Cells fetched from RPC block_number=562690 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=2.232714917s proof_verification_elapsed=20.404208ms 2024-03-20T10:50:28.322987Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562690 confidence=99.90234375 2024-03-20T10:50:28.323134Z INFO avail_light::light_client: Sleeping for 14.61143875s seconds 2024-03-20T10:50:28.323154Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:50:28.859369Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562690: 0/10. Duration: 0 2024-03-20T10:50:41.535425Z INFO avail_light::network::rpc::subscriptions: New justification at block no.: 562692, hash: 0x3b602253298ce9bec9b5b8f0c8767f14502ccaa17a003dfba77f9d90edeaf5da 2024-03-20T10:50:41.709011Z INFO avail_light::network::rpc::subscriptions: Header no.: 562692 2024-03-20T10:50:41.709557Z INFO avail_light::network::rpc::subscriptions: Number of matching signatures: 5/7 for block 562692, set_id 223 2024-03-20T10:50:41.709574Z INFO avail_light::network::rpc::subscriptions: Storing finality checkpoint at block 562692 2024-03-20T10:50:41.709908Z INFO avail_light::network::rpc::subscriptions: Sending finalized block 562692 2024-03-20T10:50:41.709966Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:50:42.936699Z INFO avail_light::light_client: Processing finalized block block_number=562691 block_delay=20 2024-03-20T10:50:42.936761Z INFO avail_light::light_client: Random cells generated: 10 block_number=562691 cells_requested=10 2024-03-20T10:50:43.472932Z INFO avail_light::network: Cells fetched from DHT block_number=562691 cells_total=10 cells_fetched=0 cells_verified=0 fetch_elapsed=536.136083ms proof_verification_elapsed=3.042µs 2024-03-20T10:50:46.513570Z INFO avail_light::network: Cells fetched from RPC block_number=562691 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=3.022786041s proof_verification_elapsed=17.810542ms 2024-03-20T10:50:46.513706Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562691 confidence=99.90234375 2024-03-20T10:50:46.513785Z INFO avail_light::light_client: Sleeping for 15.195224667s seconds 2024-03-20T10:50:46.513795Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:50:47.056255Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562691: 0/10. Duration: 0 ```
> **Note** > > **CONFIG FLAGS** > You can run the Avail light client with different flags to configure it according to your needs. > Detailed documentation for them can be found [in our Github repo](https://github.com/availproject/avail-light/blob/main/client/README.md#options). Building the Avail light client from source is a more advanced option that provides you with the maximum flexibility. To do so: 1. Clone the Avail light-client repo and checkout to the specified version: ```sh git clone https://github.com/availproject/avail-light.git cd avail-light ``` 2. Make sure your terminal is in the `avail-light` directory. Create a compiled build by running: ```sh cargo build --release ``` 3. This will create a new directory named `target` within `avail-light`. Navigate to `target/release` using: ```sh cd target/release ``` 4. Here you will find the `avail-light` build. Run the build using: ```sh ./avail-light --network mainnet ``` 5. If everything goes well, the client output will look like this:
Sample output ```shell 2024-03-20T10:22:23.821042Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:22:23.854448Z INFO avail_light::network: Cells fetched from RPC block_number=562606 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=466.901875ms proof_verification_elapsed=10.431583ms 2024-03-20T10:22:23.854573Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562606 confidence=99.90234375 2024-03-20T10:22:23.854635Z INFO avail_light::light_client: Sleeping for 19.965855416s seconds 2024-03-20T10:22:23.854643Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:22:24.392198Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562606: 0/10. Duration: 0 2024-03-20T10:22:43.821867Z INFO avail_light::light_client: Processing finalized block block_number=562607 block_delay=20 2024-03-20T10:22:43.821955Z INFO avail_light::light_client: Random cells generated: 10 block_number=562607 cells_requested=10 2024-03-20T10:22:44.358772Z INFO avail_light::network: Cells fetched from DHT block_number=562607 cells_total=10 cells_fetched=0 cells_verified=0 fetch_elapsed=536.778958ms proof_verification_elapsed=2.292µs 2024-03-20T10:22:45.937348Z INFO avail_light::network: Cells fetched from RPC block_number=562607 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=1.56179875s proof_verification_elapsed=16.692791ms 2024-03-20T10:22:45.938417Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562607 confidence=99.90234375 2024-03-20T10:22:45.938564Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:22:46.473163Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562607: 0/10. Duration: 0 2024-03-20T10:22:46.527044Z INFO avail_light::network::rpc::subscriptions: New justification at block no.: 562608, hash: 0xbea2a4b136c271b72314e2349577136bf7cdc7c732bc3909e280eb602b8af643 2024-03-20T10:22:46.672163Z INFO avail_light::network::rpc::subscriptions: Header no.: 562608 2024-03-20T10:22:46.673730Z INFO avail_light::network::rpc::subscriptions: Number of matching signatures: 5/7 for block 562608, set_id 223 2024-03-20T10:22:46.673755Z INFO avail_light::network::rpc::subscriptions: Storing finality checkpoint at block 562608 2024-03-20T10:22:46.674002Z INFO avail_light::network::rpc::subscriptions: Sending finalized block 562608 2024-03-20T10:22:46.674087Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:22:46.674150Z INFO avail_light::light_client: Sleeping for 19.998042125s seconds ```
[Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/about) is a Windows feature that allows you to run a Linux distribution directly on Windows, without having to set up a separate virtual machine or a dual-boot system. However, we realise that working with WSL might be inconvenient for some users. We have therefore also included instructions on how to run the Avail light client natively on Windows without having to go through any technical hassles. #### Without WSL 1. Go to the [releases page of the Avail light client repo](https://github.com/availproject/avail-light/releases), and download the `avail-light-windows-runner.zip` file of the `Latest` version. 2. Right click the downloaded file and extract it to a convenient location. 3. Then run the `availup.bat` file by double clicking it. This will start the Avail light client. 4. If everything goes well, the client output will look like this:
Sample output ```shell 2024-03-20T10:22:23.821042Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:22:23.854448Z INFO avail_light::network: Cells fetched from RPC block_number=562606 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=466.901875ms proof_verification_elapsed=10.431583ms 2024-03-20T10:22:23.854573Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562606 confidence=99.90234375 2024-03-20T10:22:23.854635Z INFO avail_light::light_client: Sleeping for 19.965855416s seconds 2024-03-20T10:22:23.854643Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:22:24.392198Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562606: 0/10. Duration: 0 2024-03-20T10:22:43.821867Z INFO avail_light::light_client: Processing finalized block block_number=562607 block_delay=20 2024-03-20T10:22:43.821955Z INFO avail_light::light_client: Random cells generated: 10 block_number=562607 cells_requested=10 2024-03-20T10:22:44.358772Z INFO avail_light::network: Cells fetched from DHT block_number=562607 cells_total=10 cells_fetched=0 cells_verified=0 fetch_elapsed=536.778958ms proof_verification_elapsed=2.292µs 2024-03-20T10:22:45.937348Z INFO avail_light::network: Cells fetched from RPC block_number=562607 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=1.56179875s proof_verification_elapsed=16.692791ms 2024-03-20T10:22:45.938417Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562607 confidence=99.90234375 2024-03-20T10:22:45.938564Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:22:46.473163Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562607: 0/10. Duration: 0 2024-03-20T10:22:46.527044Z INFO avail_light::network::rpc::subscriptions: New justification at block no.: 562608, hash: 0xbea2a4b136c271b72314e2349577136bf7cdc7c732bc3909e280eb602b8af643 2024-03-20T10:22:46.672163Z INFO avail_light::network::rpc::subscriptions: Header no.: 562608 2024-03-20T10:22:46.673730Z INFO avail_light::network::rpc::subscriptions: Number of matching signatures: 5/7 for block 562608, set_id 223 2024-03-20T10:22:46.673755Z INFO avail_light::network::rpc::subscriptions: Storing finality checkpoint at block 562608 2024-03-20T10:22:46.674002Z INFO avail_light::network::rpc::subscriptions: Sending finalized block 562608 2024-03-20T10:22:46.674087Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:22:46.674150Z INFO avail_light::light_client: Sleeping for 19.998042125s seconds ```
> **Note** > > Please note that trying to download and run a precompiled binary via a `.zip` file might result in > windows warning you about the file being potentially harmful. You will need to bypass this warning to run the light client. #### With WSL To install WSL on your Windows machine: 1. Open `Windows Powershell`, and run the following command: ```sh wsl --install --no-distribution ``` 2. This step takes some time and you will need to restart your computer once the installation is complete. 3. After restarting, run the following command in Powershell to see a list of all available Linux distributions: ```sh wsl --list --online ``` 4. You can install any of those listed distributions, but we will be going with `ubuntu` for this guide: ```sh wsl --install ubuntu ``` This step will prompt you to enter a username and password for your local Ubuntu installation. 5. Once inside the Ubuntu terminal, run the following command to install the required dependencies: ```sh sudo apt install build-essential && sudo apt install clang ``` > **Note** > > It is also highly recommended to upgrade all your dependencies to their latest recommended versions whenever > you set up a new Linux machine. You can do that by running: > > ```sh > sudo apt-get update && sudo apt upgrade > ``` 6. Once you have an up to date Linux distro (in this case Ubuntu) running, you can initialize the Avail light client by simply running: ```sh curl -sL1 avail.sh | bash ``` 7. If everything goes well, the client output will look like this:
Sample output ```shell 2024-03-20T10:22:23.821042Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:22:23.854448Z INFO avail_light::network: Cells fetched from RPC block_number=562606 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=466.901875ms proof_verification_elapsed=10.431583ms 2024-03-20T10:22:23.854573Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562606 confidence=99.90234375 2024-03-20T10:22:23.854635Z INFO avail_light::light_client: Sleeping for 19.965855416s seconds 2024-03-20T10:22:23.854643Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:22:24.392198Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562606: 0/10. Duration: 0 2024-03-20T10:22:43.821867Z INFO avail_light::light_client: Processing finalized block block_number=562607 block_delay=20 2024-03-20T10:22:43.821955Z INFO avail_light::light_client: Random cells generated: 10 block_number=562607 cells_requested=10 2024-03-20T10:22:44.358772Z INFO avail_light::network: Cells fetched from DHT block_number=562607 cells_total=10 cells_fetched=0 cells_verified=0 fetch_elapsed=536.778958ms proof_verification_elapsed=2.292µs 2024-03-20T10:22:45.937348Z INFO avail_light::network: Cells fetched from RPC block_number=562607 cells_total=10 cells_fetched=10 cells_verified=10 fetch_elapsed=1.56179875s proof_verification_elapsed=16.692791ms 2024-03-20T10:22:45.938417Z INFO avail_light::light_client: Confidence factor: 99.90234375 block_number=562607 confidence=99.90234375 2024-03-20T10:22:45.938564Z INFO avail_light::api::v2: Message published to clients topic=ConfidenceAchieved published=0 failed=0 2024-03-20T10:22:46.473163Z INFO avail_light::network::p2p::event_loop: Cell upload success rate for block 562607: 0/10. Duration: 0 2024-03-20T10:22:46.527044Z INFO avail_light::network::rpc::subscriptions: New justification at block no.: 562608, hash: 0xbea2a4b136c271b72314e2349577136bf7cdc7c732bc3909e280eb602b8af643 2024-03-20T10:22:46.672163Z INFO avail_light::network::rpc::subscriptions: Header no.: 562608 2024-03-20T10:22:46.673730Z INFO avail_light::network::rpc::subscriptions: Number of matching signatures: 5/7 for block 562608, set_id 223 2024-03-20T10:22:46.673755Z INFO avail_light::network::rpc::subscriptions: Storing finality checkpoint at block 562608 2024-03-20T10:22:46.674002Z INFO avail_light::network::rpc::subscriptions: Sending finalized block 562608 2024-03-20T10:22:46.674087Z INFO avail_light::api::v2: Message published to clients topic=HeaderVerified published=0 failed=0 2024-03-20T10:22:46.674150Z INFO avail_light::light_client: Sleeping for 19.998042125s seconds ```
### Setting your identity using `identity.toml` > **Note** > > **ONLY IF YOU WANT TO SUBMIT DATA TO AVAIL DA USING THE LIGHT CLIENT** > The light client API exposes a method you can use to submit data to Avail DA, but to do so the API needs access to an Avail account with some AVAIL tokens. \\ > > > *You don't need to set an identity if you only want your client to fetch data from the network.* * Whenever you run an Avail LC, you will notice a file named `identity.toml` being created in the same directory as the binary. This is a default file that contains a random `seed phrase` that represents your identity on the network. * You can also set your own `seed phrase` by creating an `identity.toml` file, and passing it as an argument using the `--identity` flag. ### Initializing the `App-client` mode 1. create an `identity.toml` file anywhere in your system. 2. Initialize a variable named `avail_secret_seed_phrase` like this: ```toml avail_secret_seed_phrase = 'AvailDA rice is demon the pair best almond DA walnut solution walrus out tube there' ``` 3. Pass this file to the light client using the `--identity` flag like this. This could look something like this: #### availup > **Note** > > **CONFIG FLAGS** > Availup supports many different config flags to support your needs. > Detailed documentation for them can be found [in our Github repo](https://github.com/availproject/availup?tab=readme-ov-file#availup). **[`availup`](https://github.com/availproject/availup)** is the recommended way of running the Avail light client for most users. `availup` is a shell wrapper that allows you to spin up your own instance of the Avail light client with a simple `curl` command. > **Note** > > To run the Avail LC using `availup`, make sure you have [`curl`](https://curl.se/) installed on your system. To check, quickly: > > ```sh > curl --version > ``` 1. To spin up an Avail light client on the Turing testnet, just run this one command in your terminal: ```sh curl -sL1 avail.sh | bash -s -- --app_id 18 --network turing --identity identity.toml ``` 2. If everything goes well, the client output will look like this: > **Note** > > Please note this command worked for a system where the `identity.toml` file was in the same directory as the terminal. > You will need to pass the full path to the `identity.toml` file if it is located elsewhere. #### Run pre-built binary > **Note** > > **CONFIG FLAGS** > You can run the Avail light client with different flags to configure it according to your needs. > Detailed documentation for them can be found [in our Github repo](https://github.com/availproject/avail-light/blob/main/client/README.md#options). You can also download and run a pre-built binary of the Avail light client. To do so: 1. Download the [recommended version of the binary](https://github.com/availproject/avail-light/releases) that is compatible with your operating system. 2. Move the `.tar` file into a convenient directory and extract it to reveal the `avail-light` binary. 3. Open a terminal in that location and run: For linux machines that run on `x86_64` based Intel or `amd64` based AMD processors, run: ```sh ./avail-light-linux-amd64 --app-id 18 --network mainnet --identity identity.toml ``` #### Build from source For linux machines that run on `arm64` based processors, run: ```sh ./avail-light-linux-arm64 --app-id 18 --network mainnet --identity identity.toml ``` #### apple-x86_64 For MacOS machines that run on `x86_64` based Intel processors, run: ```sh ./avail-light-apple-x86_64 --app-id 18 --network mainnet --identity identity.toml ``` #### apple-arm64 For MacOS machines that run on newer `arm64` based M-series processors, run: ```sh ./avail-light-apple-arm64 --app-id 18 --network mainnet --identity identity.toml ``` > **Note** > > You can configure the run command with a variety of [config flags](https://github.com/availproject/avail-light/blob/main/client/README.md#options). > **Note** > > **CONFIG FLAGS** > You can run the Avail light client with different flags to configure it according to your needs. > Detailed documentation for them can be found [in our Github repo](https://github.com/availproject/avail-light/blob/main/client/README.md#options). Building the Avail light client from source is a more advanced option that provides you with the maximum flexibility. To do so: 1. Clone the Avail light-client repo and checkout to the specified version: ```sh git clone https://github.com/availproject/avail-light.git cd avail-light ``` 2. Make sure your terminal is in the `avail-light` directory. Create a compiled build by running: ```sh cargo build --release ``` 3. This will create a new directory named `target` within `avail-light`. Navigate to `target/release` using: ```sh cd target/release ``` 4. Here you will find the `avail-light` build. Run the build using: ```sh ./avail-light --app-id 18 --network mainnet --identity identity.toml ``` ### The Light Client Lift-off challenge > **Warning** > > The Avail LC challenge has now ended. Please note that no member of the Avail team will personally reach out > **to ask you for any personal information or payment**. Rewards for the challenge can only be claimed from the official > claims page. In case of any queries, you can join our Discord server. ### Introduction to Avail light clients ## System Requirements This is the hardware configuration required to set up an Avail light client: | Component | Minimum | Recommended | | ---------------------------- | :-----: | :---------: | | RAM | 512MB | 1 GB | | CPU (amd64/x86 architecture) | 2 core | 4 core | {/* | Storage (SSD) | 20-40 GB | 200-300 GB | */} > **Note** > > **JUST LOOKING FOR INSTRUCTIONS?** > If you're not interested in theory, skip [to this link](/docs/da/operate/run-a-light-client/light-client) for instructions on how to run an Avail light client. ## Introduction Avail light client (LC) lets you interact with Avail DA without requiring a full node and without trust assumptions towards remote peers. This is accomplished by leveraging **Data Availability Sampling (DAS)** performed by the light client on every newly created block. The light client listens on the Avail network for finalized blocks and performs DAS on a predetermined number of cells on each new block. After successful block verification, **block confidence** is calculated for a number of cells in the matrix, with the number depending on the percentage of certainty the users wishes to achieve.

> This screenshot is from a purely in-browser interface built by the Avail team that uses a light client to determine the confidence of blocks in real time. You can check it out at [light.avail.tools](https://light.avail.tools/). Light client functionality is separated into two logical parts - the *light client* and the *app client*. While the LC is primarily focused on DAS, the app client is used to perform data reconstruction. ## Light client The **light client** mode of operation is active regardless of whether the app client is also active or not. Light client connects to an Avail node via a WebSocket connection and waits for a newly finalized block, with the header containing its KZG commitments. > **Note** > > Avail blocks are chunked and divided into equal sized cells as a part of that blocks matrix. Each row in the matrix is then erasure coded using **Reed-Solomon (RS)** erasure codes and committed with **Kate-Zaverucha-Goldberg (KZG)** commitments. On each received header the client does random sampling of the matrix cells, which are retrieved using one of two mechanisms: 1. **DHT** - the client first tries to retrieve cells via Kademlia DHT, on the LC-only high availability peer-to-peer network. 2. **RPC** - if some or all of the required cells can't be found on the DHT, LC uses RPC calls to the Avail node(s) to retrieve the data. Cells not already found in the DHT will be uploaded thus increasing blocks availability in the LC P2P network Once the data is received, light client verifies individual cells and calculates the confidence that is then stored locally. > **Note** > > Light client uses *libp2p* with **Kademlia** as a DHT implementation. Peer-to-peer network is able to perform NAT traversal, both symmetric and asymmetric, enabling easy connectivity with various network configurations (e.g. symmetric and asymmetric NAT). > **Note** > > On fresh startup, the LC performs a block sync with the node, using both DHT and RPC mechanisms. The block depth to which the sync is going to be done is set with the `sync_block_depth` config parameter, which needs to be set to the max number of blocks the connected node is caching (if downloading via RPC). ## When and how to embed the light client The Avail light client plays a vital role in ensuring the availability and correctness of data within the Avail network. By employing random sampling, it achieves security levels comparable to full nodes. Furthermore, by leveraging the peer-to-peer network, it enhances overall data availability while reducing the load on full nodes. The light client is capable of downloading and verifying application-specific data submitted to Avail, which can be conveniently queried using the light client API. > **Note** > > You can check out all the different methods supported by the Avail light client in our [Light Client API Reference](/docs/da/api-reference/avail-lc-api). The light client exposes an HTTP API that enables users to query the status, confidence, and application data for each processed block. When a block is finalized in Avail, the light client performs random sampling and verification, calculates confidence in the given block data, and if the confidence is high, retrieves the application data from the block. This data is then verified and stored locally for easy access. ### Bridge between Avail & Base ## Video guide If Youtube is more your style, you can watch the video guide below, or else you can just refer to the written guide below this section.